From e5eef19692dda166b94a29a595a692264619cbeb Mon Sep 17 00:00:00 2001 From: kadmin Date: Mon, 21 Dec 2020 09:50:56 +0000 Subject: [PATCH 1/4] Optimization in macro derive More minor opts Rm unnecessary boxes --- .../src/deriving/cmp/partial_ord.rs | 8 +- .../src/deriving/decodable.rs | 9 +- .../src/deriving/encodable.rs | 9 +- .../src/deriving/generic/mod.rs | 185 +++++++++--------- .../src/deriving/generic/ty.rs | 30 +-- .../rustc_builtin_macros/src/deriving/mod.rs | 19 +- 6 files changed, 127 insertions(+), 133 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 21174ca4c8bf9..20b53ef4e17cb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -38,12 +38,8 @@ pub fn expand_deriving_partial_ord( } let ordering_ty = Literal(path_std!(cmp::Ordering)); - let ret_ty = Literal(Path::new_( - pathvec_std!(option::Option), - None, - vec![Box::new(ordering_ty)], - PathKind::Std, - )); + let ret_ty = + Literal(Path::new_(pathvec_std!(option::Option), None, vec![ordering_ty], PathKind::Std)); let inline = cx.meta_word(span, sym::inline); let attrs = vec![cx.attribute(inline)]; diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index df69f6c90d813..8490650a66152 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -45,13 +45,8 @@ pub fn expand_deriving_rustc_decodable( pathvec_std!(result::Result), None, vec![ - Box::new(Self_), - Box::new(Literal(Path::new_( - vec![typaram, sym::Error], - None, - vec![], - PathKind::Local, - ))), + Self_, + Literal(Path::new_(vec![typaram, sym::Error], None, vec![], PathKind::Local)), ], PathKind::Std, )), diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 62aa1cbfbf265..332a5e4c2a966 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -135,13 +135,8 @@ pub fn expand_deriving_rustc_encodable( pathvec_std!(result::Result), None, vec![ - Box::new(Tuple(Vec::new())), - Box::new(Literal(Path::new_( - vec![typaram, sym::Error], - None, - vec![], - PathKind::Local, - ))), + Tuple(Vec::new()), + Literal(Path::new_(vec![typaram, sym::Error], None, vec![], PathKind::Local)), ], PathKind::Std, )), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index e78d1368b357e..a1373b262fa8e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -212,15 +212,15 @@ pub struct TraitDef<'a> { /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder` pub generics: Bounds, + pub methods: Vec>, + + pub associated_types: Vec<(Ident, Ty)>, + /// Is it an `unsafe` trait? pub is_unsafe: bool, /// Can this trait be derived for unions? pub supports_unions: bool, - - pub methods: Vec>, - - pub associated_types: Vec<(Ident, Ty)>, } pub struct MethodDef<'a> { @@ -237,18 +237,18 @@ pub struct MethodDef<'a> { /// Arguments other than the self argument pub args: Vec<(Ty, Symbol)>, - /// Returns type + /// Return type pub ret_ty: Ty, pub attributes: Vec, - // Is it an `unsafe fn`? - pub is_unsafe: bool, - /// Can we combine fieldless variants for enums into a single match arm? pub unify_fieldless_variants: bool, pub combine_substructure: RefCell>, + + /// Is it an `unsafe fn`? + pub is_unsafe: bool, } /// All the data about the data structure/method being derived upon. @@ -451,23 +451,27 @@ impl<'a> TraitDef<'a> { }; // Keep the lint attributes of the previous item to control how the // generated implementations are linted - let mut attrs = newitem.attrs.clone(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::stable, - sym::unstable, - ] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); + let attrs = newitem + .attrs + .iter() + .cloned() + .chain( + item.attrs + .iter() + .filter(|a| { + [ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::stable, + sym::unstable, + ] + .contains(&a.name_or_empty()) + }) + .cloned(), + ) + .collect(); push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() }))) } _ => unreachable!(), @@ -542,7 +546,7 @@ impl<'a> TraitDef<'a> { // Create the generic parameters params.extend(generics.params.iter().map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => param.clone(), + GenericParamKind::Lifetime { .. } | GenericParamKind::Const { .. } => param.clone(), GenericParamKind::Type { .. } => { // I don't think this can be moved out of the loop, since // a GenericBound requires an ast id @@ -561,7 +565,6 @@ impl<'a> TraitDef<'a> { cx.typaram(self.span, param.ident, vec![], bounds, None) } - GenericParamKind::Const { .. } => param.clone(), })); // and similarly for where clauses @@ -605,38 +608,37 @@ impl<'a> TraitDef<'a> { let ty_param_names: Vec = ty_params.map(|ty_param| ty_param.ident.name).collect(); - for field_ty in field_tys { + let bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + // require the current trait + .chain(iter::once(cx.trait_bound(trait_path.clone()))) + .collect(); + let preds = field_tys.iter().flat_map(|field_ty| { let tys = find_type_parameters(&field_ty, &ty_param_names, cx); - - for ty in tys { + tys.into_iter().filter_map(|ty| { // if we have already handled this type, skip it if let ast::TyKind::Path(_, ref p) = ty.kind { if p.segments.len() == 1 && ty_param_names.contains(&p.segments[0].ident.name) { - continue; - }; + return None; + } } - let mut bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) - .collect(); - - // require the current trait - bounds.push(cx.trait_bound(trait_path.clone())); let predicate = ast::WhereBoundPredicate { span: self.span, bound_generic_params: Vec::new(), bounded_ty: ty, - bounds, + bounds: bounds.clone(), }; let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } - } + Some(predicate) + }) + }); + where_clause.predicates.extend(preds); } } @@ -678,11 +680,14 @@ impl<'a> TraitDef<'a> { cx.attribute(list) }; - let mut a = vec![attr, unused_qual]; - a.extend(self.attributes.iter().cloned()); + let a = iter::once(attr) + .chain(iter::once(unused_qual)) + .chain(self.attributes.iter().cloned()) + .collect(); let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No }; - + let mut items = methods; + items.extend(associated_types); cx.item( self.span, Ident::invalid(), @@ -695,7 +700,7 @@ impl<'a> TraitDef<'a> { generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, - items: methods.into_iter().chain(associated_types).collect(), + items, }, ) } @@ -709,9 +714,6 @@ impl<'a> TraitDef<'a> { from_scratch: bool, use_temporaries: bool, ) -> P { - let field_tys: Vec> = - struct_def.fields().iter().map(|field| field.ty.clone()).collect(); - let methods = self .methods .iter() @@ -744,6 +746,8 @@ impl<'a> TraitDef<'a> { }) .collect(); + let field_tys: Vec> = + struct_def.fields().iter().map(|field| field.ty.clone()).collect(); self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } @@ -755,11 +759,11 @@ impl<'a> TraitDef<'a> { generics: &Generics, from_scratch: bool, ) -> P { - let mut field_tys = Vec::new(); - - for variant in &enum_def.variants { - field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone())); - } + let field_tys = enum_def + .variants + .iter() + .flat_map(|variant| variant.data.fields().iter().map(|field| field.ty.clone())) + .collect(); let methods = self .methods @@ -980,22 +984,22 @@ impl<'a> MethodDef<'a> { nonself_args: &[P], use_temporaries: bool, ) -> P { - let mut raw_fields = Vec::new(); // Vec<[fields of self], - // [fields of next Self arg], [etc]> - let mut patterns = Vec::new(); - for i in 0..self_args.len() { - let struct_path = cx.path(trait_.span, vec![type_ident]); - let (pat, ident_expr) = trait_.create_struct_pattern( - cx, - struct_path, - struct_def, - &format!("__self_{}", i), - ast::Mutability::Not, - use_temporaries, - ); - patterns.push(pat); - raw_fields.push(ident_expr); - } + // raw_fields: Vec<[fields of self], + // patterns: [fields of next Self arg], [etc]> + let (patterns, raw_fields): (Vec<_>, Vec<_>) = (0..self_args.len()) + .map(|i| { + let struct_path = cx.path(trait_.span, vec![type_ident]); + let (pat, ident_expr) = trait_.create_struct_pattern( + cx, + struct_path, + struct_def, + &format!("__self_{}", i), + ast::Mutability::Not, + use_temporaries, + ); + (pat, ident_expr) + }) + .unzip(); // transpose raw_fields let fields = if !raw_fields.is_empty() { @@ -1555,18 +1559,21 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability, use_temporaries: bool, ) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { - let mut paths = Vec::new(); - let mut ident_exprs = Vec::new(); - for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span); - paths.push(ident.with_span_pos(sp)); - let val = cx.expr_path(cx.path_ident(sp, ident)); - let val = if use_temporaries { val } else { cx.expr_deref(sp, val) }; - let val = cx.expr(sp, ast::ExprKind::Paren(val)); - - ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..])); - } + let (paths, ident_exprs): (Vec<_>, Vec<_>) = struct_def + .fields() + .iter() + .enumerate() + .map(|(i, struct_field)| { + let sp = struct_field.span.with_ctxt(self.span.ctxt()); + let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span); + + let val = cx.expr_path(cx.path_ident(sp, ident)); + let val = if use_temporaries { val } else { cx.expr_deref(sp, val) }; + let val = cx.expr(sp, ast::ExprKind::Paren(val)); + + (ident.with_span_pos(sp), (sp, struct_field.ident, val, &struct_field.attrs[..])) + }) + .unzip(); let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries); let pattern = match *struct_def { @@ -1575,11 +1582,13 @@ impl<'a> TraitDef<'a> { .into_iter() .zip(&ident_exprs) .map(|(pat, &(sp, ident, ..))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } + let ident = if let Some(ident) = ident { + ident + } else { + cx.span_bug(sp, "a braced struct with unnamed fields in `derive`") + }; ast::FieldPat { - ident: ident.unwrap(), + ident: ident, is_shorthand: false, attrs: ast::AttrVec::new(), id: ast::DUMMY_NODE_ID, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 6b7d0e1f204b5..be7e035d33031 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -27,7 +27,7 @@ pub enum PtrTy { pub struct Path { path: Vec, lifetime: Option, - params: Vec>, + params: Vec, kind: PathKind, } @@ -48,7 +48,7 @@ impl Path { pub fn new_( path: Vec, lifetime: Option, - params: Vec>, + params: Vec, kind: PathKind, ) -> Path { Path { path, lifetime, params, kind } @@ -70,22 +70,18 @@ impl Path { self_ty: Ident, self_generics: &Generics, ) -> ast::Path { - let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); + let idents = self.path.iter().map(|s| Ident::new(*s, span)); let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys: Vec> = - self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - let params = lt - .into_iter() - .map(GenericArg::Lifetime) - .chain(tys.into_iter().map(GenericArg::Type)) - .collect(); + let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); + let params = lt.map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect(); match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params), - PathKind::Local => cx.path_all(span, false, idents, params), + PathKind::Global => cx.path_all(span, true, idents.collect(), params), + PathKind::Local => cx.path_all(span, false, idents.collect(), params), PathKind::Std => { let def_site = cx.with_def_site_ctxt(DUMMY_SP); - idents.insert(0, Ident::new(kw::DollarCrate, def_site)); + let idents = + std::iter::once(Ident::new(kw::DollarCrate, def_site)).chain(idents).collect(); cx.path_all(span, false, idents, params) } } @@ -128,8 +124,12 @@ fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option) -> Option, span: Span, lt: &Option) -> Vec { - mk_lifetime(cx, span, lt).into_iter().collect() +fn mk_lifetimes( + cx: &ExtCtxt<'_>, + span: Span, + lt: &Option, +) -> impl Iterator { + mk_lifetime(cx, span, lt).into_iter() } impl Ty { diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 3c8bf12b3d415..df0a95e09b9e2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -164,16 +164,15 @@ fn inject_impl_of_structural_trait( // Keep the lint and stability attributes of the original item, to control // how the generated implementation is linted. - let mut attrs = Vec::new(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); + let attrs: Vec<_> = item + .attrs + .iter() + .filter(|a| { + [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] + .contains(&a.name_or_empty()) + }) + .cloned() + .collect(); let newitem = cx.item( span, From b2c51ca1063e70c1041754c8ba6e268d69a24323 Mon Sep 17 00:00:00 2001 From: kadmin Date: Thu, 24 Dec 2020 07:22:34 +0000 Subject: [PATCH 2/4] Smoe more minor optimizations Really just one batched allocation, and the rest are style changes --- compiler/rustc_expand/src/base.rs | 35 +++++++++---------- compiler/rustc_resolve/src/macros.rs | 18 +++++----- compiler/rustc_typeck/src/astconv/generics.rs | 3 +- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 774a0764d114f..f5475439adf89 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1071,26 +1071,25 @@ impl<'a> ExtCtxt<'a> { ) -> Result> { let path = path.into(); + if path.is_absolute() { + return Ok(path); + } // Relative paths are resolved relative to the file in which they are found // after macro expansion (that is, they are unhygienic). - if !path.is_absolute() { - let callsite = span.source_callsite(); - let mut result = match self.source_map().span_to_unmapped_path(callsite) { - FileName::Real(name) => name.into_local_path(), - FileName::DocTest(path, _) => path, - other => { - return Err(self.struct_span_err( - span, - &format!("cannot resolve relative path in non-file source `{}`", other), - )); - } - }; - result.pop(); - result.push(path); - Ok(result) - } else { - Ok(path) - } + let callsite = span.source_callsite(); + let mut result = match self.source_map().span_to_unmapped_path(callsite) { + FileName::Real(name) => name.into_local_path(), + FileName::DocTest(path, _) => path, + other => { + return Err(self.struct_span_err( + span, + &format!("cannot resolve relative path in non-file source `{}`", other), + )); + } + }; + result.pop(); + result.push(path); + Ok(result) } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5ad7c83ca36af..5312b62cc73dd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -263,10 +263,10 @@ impl<'a> ResolverExpand for Resolver<'a> { // than by individual derives. // - Derives in the container need to know whether one of them is a built-in `Copy`. // FIXME: Try to avoid repeated resolutions for derives here and in expansion. - let mut exts = Vec::new(); let mut helper_attrs = Vec::new(); - for path in derives { - exts.push( + let exts = derives + .iter() + .map(|path| { match self.resolve_macro_path( path, Some(MacroKind::Derive), @@ -288,15 +288,15 @@ impl<'a> ResolverExpand for Resolver<'a> { if ext.is_derive_copy { self.containers_deriving_copy.insert(invoc_id); } - ext + Ok(ext) } Ok(_) | Err(Determinacy::Determined) => { - self.dummy_ext(MacroKind::Derive) + Ok(self.dummy_ext(MacroKind::Derive)) } - Err(Determinacy::Undetermined) => return Err(Indeterminate), - }, - ) - } + Err(Determinacy::Undetermined) => Err(Indeterminate), + } + }) + .collect::, _>>()?; self.helper_attrs.insert(invoc_id, helper_attrs); return Ok(InvocationRes::DeriveContainer(exts)); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index a3a2b8967c606..ce9b98848ba81 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -347,13 +347,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { seg: &hir::PathSegment<'_>, is_method_call: bool, ) -> GenericArgCountResult { - let empty_args = hir::GenericArgs::none(); let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( tcx, span, def, - if let Some(ref args) = seg.args { args } else { &empty_args }, + seg.args.unwrap_or(&hir::GenericArgs::none()), if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value }, def.parent.is_none() && def.has_self, // `has_self` seg.infer_args || suppress_mismatch, // `infer_args` From 9c9a046004a16dbfba1bfb633964982ea3cdbef3 Mon Sep 17 00:00:00 2001 From: kadmin Date: Fri, 25 Dec 2020 01:10:06 +0000 Subject: [PATCH 3/4] Convert dyn AstConv to AstConv I expect this to have a perf impact because I think this is responsible for lowering types from hir, and that the reason that lowering builtin derives is slow is because the paths are longer. That lead me to find this, which I'm not sure if this is on the hot path or not. If it is, this should certainly be a perf win. --- compiler/rustc_typeck/src/astconv/errors.rs | 661 ++- compiler/rustc_typeck/src/astconv/generics.rs | 925 ++-- compiler/rustc_typeck/src/astconv/mod.rs | 3924 +++++++++-------- compiler/rustc_typeck/src/check/closure.rs | 18 +- compiler/rustc_typeck/src/check/coercion.rs | 6 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 14 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 8 +- .../rustc_typeck/src/check/fn_ctxt/mod.rs | 4 +- .../src/check/fn_ctxt/suggestions.rs | 4 +- .../rustc_typeck/src/check/method/confirm.rs | 8 +- compiler/rustc_typeck/src/check/mod.rs | 6 +- compiler/rustc_typeck/src/collect.rs | 52 +- .../rustc_typeck/src/collect/item_bounds.rs | 6 +- compiler/rustc_typeck/src/lib.rs | 5 +- 14 files changed, 2805 insertions(+), 2836 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index b04acd9660d45..42b7547c05364 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -11,378 +11,373 @@ use rustc_span::{Span, DUMMY_SP}; use std::collections::BTreeSet; -impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - /// On missing type parameters, emit an E0393 error and provide a structured suggestion using - /// the type parameter's name as a placeholder. - pub(crate) fn complain_about_missing_type_params( - &self, - missing_type_params: Vec, - def_id: DefId, - span: Span, - empty_generic_args: bool, - ) { - if missing_type_params.is_empty() { - return; - } - let display = - missing_type_params.iter().map(|n| format!("`{}`", n)).collect::>().join(", "); - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0393, - "the type parameter{} {} must be explicitly specified", +/// On missing type parameters, emit an E0393 error and provide a structured suggestion using +/// the type parameter's name as a placeholder. +pub(crate) fn complain_about_missing_type_params<'tcx>( + astconv: &impl AstConv<'tcx>, + missing_type_params: Vec, + def_id: DefId, + span: Span, + empty_generic_args: bool, +) { + if missing_type_params.is_empty() { + return; + } + let display = + missing_type_params.iter().map(|n| format!("`{}`", n)).collect::>().join(", "); + let tcx = astconv.tcx(); + let mut err = struct_span_err!( + tcx.sess, + span, + E0393, + "the type parameter{} {} must be explicitly specified", + pluralize!(missing_type_params.len()), + display, + ); + err.span_label( + tcx.def_span(def_id), + &format!( + "type parameter{} {} must be specified for this", pluralize!(missing_type_params.len()), display, - ); - err.span_label( - self.tcx().def_span(def_id), - &format!( - "type parameter{} {} must be specified for this", - pluralize!(missing_type_params.len()), - display, - ), - ); - let mut suggested = false; - if let (Ok(snippet), true) = ( - self.tcx().sess.source_map().span_to_snippet(span), - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. - empty_generic_args, - ) { - if snippet.ends_with('>') { - // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion - // we would have to preserve the right order. For now, as clearly the user is - // aware of the syntax, we do nothing. - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - err.span_suggestion( - span, - &format!( - "set the type parameter{plural} to the desired type{plural}", - plural = pluralize!(missing_type_params.len()), - ), - format!("{}<{}>", snippet, missing_type_params.join(", ")), - Applicability::HasPlaceholders, - ); - suggested = true; - } - } - if !suggested { - err.span_label( + ), + ); + let mut suggested = false; + if let (Ok(snippet), true) = ( + tcx.sess.source_map().span_to_snippet(span), + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + empty_generic_args, + ) { + if snippet.ends_with('>') { + // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion + // we would have to preserve the right order. For now, as clearly the user is + // aware of the syntax, we do nothing. + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + err.span_suggestion( span, - format!( - "missing reference{} to {}", - pluralize!(missing_type_params.len()), - display, + &format!( + "set the type parameter{plural} to the desired type{plural}", + plural = pluralize!(missing_type_params.len()), ), + format!("{}<{}>", snippet, missing_type_params.join(", ")), + Applicability::HasPlaceholders, ); + suggested = true; } - err.note( - "because of the default `Self` reference, type parameters must be \ - specified on object types", + } + if !suggested { + err.span_label( + span, + format!("missing reference{} to {}", pluralize!(missing_type_params.len()), display,), ); - err.emit(); } + err.note( + "because of the default `Self` reference, type parameters must be \ + specified on object types", + ); + err.emit(); +} - /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit - /// an error and attempt to build a reasonable structured suggestion. - pub(crate) fn complain_about_internal_fn_trait( - &self, - span: Span, - trait_def_id: DefId, - trait_segment: &'a hir::PathSegment<'a>, - ) { - let trait_def = self.tcx().trait_def(trait_def_id); - - if !self.tcx().features().unboxed_closures - && trait_segment.generic_args().parenthesized != trait_def.paren_sugar - { - let sess = &self.tcx().sess.parse_sess; - // For now, require that parenthetical notation be used only with `Fn()` etc. - let (msg, sugg) = if trait_def.paren_sugar { - ( - "the precise format of `Fn`-family traits' type parameters is subject to \ - change", - Some(format!( - "{}{} -> {}", - trait_segment.ident, - trait_segment - .args - .as_ref() - .and_then(|args| args.args.get(0)) - .and_then(|arg| match arg { - hir::GenericArg::Type(ty) => match ty.kind { - hir::TyKind::Tup(t) => t - .iter() - .map(|e| sess.source_map().span_to_snippet(e.span)) - .collect::, _>>() - .map(|a| a.join(", ")), - _ => sess.source_map().span_to_snippet(ty.span), - } - .map(|s| format!("({})", s)) - .ok(), - _ => None, - }) - .unwrap_or_else(|| "()".to_string()), - trait_segment - .generic_args() - .bindings - .iter() - .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { - (true, hir::TypeBindingKind::Equality { ty }) => { - sess.source_map().span_to_snippet(ty.span).ok() - } - _ => None, - }) - .unwrap_or_else(|| "()".to_string()), - )), - ) - } else { - ("parenthetical notation is only stable when used with `Fn`-family traits", None) - }; - let mut err = feature_err(sess, sym::unboxed_closures, span, msg); - if let Some(sugg) = sugg { - let msg = "use parenthetical notation instead"; - err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); - } - err.emit(); - } - } +/// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit +/// an error and attempt to build a reasonable structured suggestion. +pub(crate) fn complain_about_internal_fn_trait<'a, 'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + trait_def_id: DefId, + trait_segment: &'a hir::PathSegment<'a>, +) { + let tcx = astconv.tcx(); + let trait_def = tcx.trait_def(trait_def_id); - pub(crate) fn complain_about_assoc_type_not_found( - &self, - all_candidates: impl Fn() -> I, - ty_param_name: &str, - assoc_name: Ident, - span: Span, - ) where - I: Iterator>, + if !tcx.features().unboxed_closures + && trait_segment.generic_args().parenthesized != trait_def.paren_sugar { - // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a - // valid span, so we point at the whole path segment instead. - let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0220, - "associated type `{}` not found for `{}`", - assoc_name, - ty_param_name - ); - - let all_candidate_names: Vec<_> = all_candidates() - .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .flatten() - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, + let sess = &tcx.sess.parse_sess; + // For now, require that parenthetical notation be used only with `Fn()` etc. + let (msg, sugg) = if trait_def.paren_sugar { + ( + "the precise format of `Fn`-family traits' type parameters is subject to \ + change", + Some(format!( + "{}{} -> {}", + trait_segment.ident, + trait_segment + .args + .as_ref() + .and_then(|args| args.args.get(0)) + .and_then(|arg| match arg { + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Tup(t) => t + .iter() + .map(|e| sess.source_map().span_to_snippet(e.span)) + .collect::, _>>() + .map(|a| a.join(", ")), + _ => sess.source_map().span_to_snippet(ty.span), + } + .map(|s| format!("({})", s)) + .ok(), + _ => None, + }) + .unwrap_or_else(|| "()".to_string()), + trait_segment + .generic_args() + .bindings + .iter() + .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { + (true, hir::TypeBindingKind::Equality { ty }) => { + sess.source_map().span_to_snippet(ty.span).ok() + } + _ => None, + }) + .unwrap_or_else(|| "()".to_string()), + )), ) - .collect(); - - if let (Some(suggested_name), true) = ( - find_best_match_for_name(&all_candidate_names, assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { - err.span_suggestion( - assoc_name.span, - "there is an associated type with a similar name", - suggested_name.to_string(), - Applicability::MaybeIncorrect, - ); } else { - err.span_label(span, format!("associated type `{}` not found", assoc_name)); + ("parenthetical notation is only stable when used with `Fn`-family traits", None) + }; + let mut err = feature_err(sess, sym::unboxed_closures, span, msg); + if let Some(sugg) = sugg { + let msg = "use parenthetical notation instead"; + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); } - err.emit(); } +} + +pub(crate) fn complain_about_assoc_type_not_found<'tcx, I>( + astconv: &impl AstConv<'tcx>, + all_candidates: impl Fn() -> I, + ty_param_name: &str, + assoc_name: Ident, + span: Span, +) where + I: Iterator>, +{ + // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a + // valid span, so we point at the whole path segment instead. + let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; + let tcx = astconv.tcx(); + let mut err = struct_span_err!( + tcx.sess, + span, + E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name + ); + + let all_candidate_names: Vec<_> = all_candidates() + .map(|r| tcx.associated_items(r.def_id()).in_definition_order()) + .flatten() + .filter_map( + |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, + ) + .collect(); - /// When there are any missing associated types, emit an E0191 error and attempt to supply a - /// reasonable suggestion on how to write it. For the case of multiple associated types in the - /// same trait bound have the same name (as they come from different super-traits), we instead - /// emit a generic note suggesting using a `where` clause to constraint instead. - pub(crate) fn complain_about_missing_associated_types( - &self, - associated_types: FxHashMap>, - potential_assoc_types: Vec, - trait_bounds: &[hir::PolyTraitRef<'_>], + if let (Some(suggested_name), true) = ( + find_best_match_for_name(&all_candidate_names, assoc_name.name, None), + assoc_name.span != DUMMY_SP, ) { - if associated_types.values().all(|v| v.is_empty()) { - return; - } - let tcx = self.tcx(); - // FIXME: Marked `mut` so that we can replace the spans further below with a more - // appropriate one, but this should be handled earlier in the span assignment. - let mut associated_types: FxHashMap> = associated_types - .into_iter() - .map(|(span, def_ids)| { - (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) - }) - .collect(); - let mut names = vec![]; + err.span_suggestion( + assoc_name.span, + "there is an associated type with a similar name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(span, format!("associated type `{}` not found", assoc_name)); + } + + err.emit(); +} - // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and - // `issue-22560.rs`. - let mut trait_bound_spans: Vec = vec![]; - for (span, items) in &associated_types { - if !items.is_empty() { - trait_bound_spans.push(*span); +/// When there are any missing associated types, emit an E0191 error and attempt to supply a +/// reasonable suggestion on how to write it. For the case of multiple associated types in the +/// same trait bound have the same name (as they come from different super-traits), we instead +/// emit a generic note suggesting using a `where` clause to constraint instead. +pub(crate) fn complain_about_missing_associated_types<'tcx>( + astconv: &impl AstConv<'tcx>, + associated_types: FxHashMap>, + potential_assoc_types: Vec, + trait_bounds: &[hir::PolyTraitRef<'_>], +) { + if associated_types.values().all(|v| v.is_empty()) { + return; + } + let tcx = astconv.tcx(); + // FIXME: Marked `mut` so that we can replace the spans further below with a more + // appropriate one, but this should be handled earlier in the span assignment. + let mut associated_types: FxHashMap> = associated_types + .into_iter() + .map(|(span, def_ids)| { + (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) + }) + .collect(); + let mut names = vec![]; + + // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and + // `issue-22560.rs`. + let mut trait_bound_spans: Vec = vec![]; + for (span, items) in &associated_types { + if !items.is_empty() { + trait_bound_spans.push(*span); + } + for assoc_item in items { + let trait_def_id = assoc_item.container.id(); + names.push(format!( + "`{}` (from trait `{}`)", + assoc_item.ident, + tcx.def_path_str(trait_def_id), + )); + } + } + if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { + match &bound.trait_ref.path.segments[..] { + // FIXME: `trait_ref.path.span` can point to a full path with multiple + // segments, even though `trait_ref.path.segments` is of length `1`. Work + // around that bug here, even though it should be fixed elsewhere. + // This would otherwise cause an invalid suggestion. For an example, look at + // `src/test/ui/issues/issue-28344.rs` where instead of the following: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^ help: specify the associated type: + // | `BitXor` + // + // we would output: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^^^^^^^^ help: specify the associated type: + // | `BitXor::bitor` + [segment] if segment.args.is_none() => { + trait_bound_spans = vec![segment.ident.span]; + associated_types = associated_types + .into_iter() + .map(|(_, items)| (segment.ident.span, items)) + .collect(); } - for assoc_item in items { - let trait_def_id = assoc_item.container.id(); - names.push(format!( - "`{}` (from trait `{}`)", - assoc_item.ident, - tcx.def_path_str(trait_def_id), - )); + _ => {} + } + } + names.sort(); + trait_bound_spans.sort(); + let mut err = struct_span_err!( + tcx.sess, + trait_bound_spans, + E0191, + "the value of the associated type{} {} must be specified", + pluralize!(names.len()), + names.join(", "), + ); + let mut suggestions = vec![]; + let mut types_count = 0; + let mut where_constraints = vec![]; + for (span, assoc_items) in &associated_types { + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut dupes = false; + for item in assoc_items { + let prefix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + dupes = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { + err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); } } - if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { - match &bound.trait_ref.path.segments[..] { - // FIXME: `trait_ref.path.span` can point to a full path with multiple - // segments, even though `trait_ref.path.segments` is of length `1`. Work - // around that bug here, even though it should be fixed elsewhere. - // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs` where instead of the following: - // - // error[E0191]: the value of the associated type `Output` - // (from trait `std::ops::BitXor`) must be specified - // --> $DIR/issue-28344.rs:4:17 - // | - // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - // | ^^^^^^ help: specify the associated type: - // | `BitXor` - // - // we would output: - // - // error[E0191]: the value of the associated type `Output` - // (from trait `std::ops::BitXor`) must be specified - // --> $DIR/issue-28344.rs:4:17 - // | - // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - // | ^^^^^^^^^^^^^ help: specify the associated type: - // | `BitXor::bitor` - [segment] if segment.args.is_none() => { - trait_bound_spans = vec![segment.ident.span]; - associated_types = associated_types - .into_iter() - .map(|(_, items)| (segment.ident.span, items)) - .collect(); + if potential_assoc_types.len() == assoc_items.len() { + // Only suggest when the amount of missing associated types equals the number of + // extra type arguments present, as that gives us a relatively high confidence + // that the user forgot to give the associtated type's name. The canonical + // example would be trying to use `Iterator` instead of + // `Iterator`. + for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { + suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); } - _ => {} } + } else if let (Ok(snippet), false) = (tcx.sess.source_map().span_to_snippet(*span), dupes) { + let types: Vec<_> = + assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); + let code = if snippet.ends_with('>') { + // The user wrote `Trait<'a>` or similar and we don't have a type we can + // suggest, but at least we can clue them to the correct syntax + // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the + // suggestion. + format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + format!("{}<{}>", snippet, types.join(", ")) + }; + suggestions.push((*span, code)); + } else if dupes { + where_constraints.push(*span); } - names.sort(); - trait_bound_spans.sort(); - let mut err = struct_span_err!( - tcx.sess, - trait_bound_spans, - E0191, - "the value of the associated type{} {} must be specified", - pluralize!(names.len()), - names.join(", "), - ); - let mut suggestions = vec![]; - let mut types_count = 0; - let mut where_constraints = vec![]; + } + let where_msg = "consider introducing a new type parameter, adding `where` constraints \ + using the fully-qualified path to the associated types"; + if !where_constraints.is_empty() && suggestions.is_empty() { + // If there are duplicates associated type names and a single trait bound do not + // use structured suggestion, it means that there are multiple super-traits with + // the same associated type name. + err.help(where_msg); + } + if suggestions.len() != 1 { + // We don't need this label if there's an inline suggestion, show otherwise. for (span, assoc_items) in &associated_types { let mut names: FxHashMap<_, usize> = FxHashMap::default(); for item in assoc_items { types_count += 1; *names.entry(item.ident.name).or_insert(0) += 1; } - let mut dupes = false; + let mut label = vec![]; for item in assoc_items { - let prefix = if names[&item.ident.name] > 1 { + let postfix = if names[&item.ident.name] > 1 { let trait_def_id = item.container.id(); - dupes = true; - format!("{}::", tcx.def_path_str(trait_def_id)) + format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) } else { String::new() }; - if let Some(sp) = tcx.hir().span_if_local(item.def_id) { - err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); - } - } - if potential_assoc_types.len() == assoc_items.len() { - // Only suggest when the amount of missing associated types equals the number of - // extra type arguments present, as that gives us a relatively high confidence - // that the user forgot to give the associtated type's name. The canonical - // example would be trying to use `Iterator` instead of - // `Iterator`. - for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { - suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); - } - } - } else if let (Ok(snippet), false) = - (tcx.sess.source_map().span_to_snippet(*span), dupes) - { - let types: Vec<_> = - assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); - let code = if snippet.ends_with('>') { - // The user wrote `Trait<'a>` or similar and we don't have a type we can - // suggest, but at least we can clue them to the correct syntax - // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the - // suggestion. - format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - format!("{}<{}>", snippet, types.join(", ")) - }; - suggestions.push((*span, code)); - } else if dupes { - where_constraints.push(*span); + label.push(format!("`{}`{}", item.ident, postfix)); } - } - let where_msg = "consider introducing a new type parameter, adding `where` constraints \ - using the fully-qualified path to the associated types"; - if !where_constraints.is_empty() && suggestions.is_empty() { - // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with - // the same associated type name. - err.help(where_msg); - } - if suggestions.len() != 1 { - // We don't need this label if there's an inline suggestion, show otherwise. - for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); - for item in assoc_items { - types_count += 1; - *names.entry(item.ident.name).or_insert(0) += 1; - } - let mut label = vec![]; - for item in assoc_items { - let postfix = if names[&item.ident.name] > 1 { - let trait_def_id = item.container.id(); - format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) - } else { - String::new() - }; - label.push(format!("`{}`{}", item.ident, postfix)); - } - if !label.is_empty() { - err.span_label( - *span, - format!( - "associated type{} {} must be specified", - pluralize!(label.len()), - label.join(", "), - ), - ); - } + if !label.is_empty() { + err.span_label( + *span, + format!( + "associated type{} {} must be specified", + pluralize!(label.len()), + label.join(", "), + ), + ); } } - if !suggestions.is_empty() { - err.multipart_suggestion( - &format!("specify the associated type{}", pluralize!(types_count)), - suggestions, - Applicability::HasPlaceholders, - ); - if !where_constraints.is_empty() { - err.span_help(where_constraints, where_msg); - } + } + if !suggestions.is_empty() { + err.multipart_suggestion( + &format!("specify the associated type{}", pluralize!(types_count)), + suggestions, + Applicability::HasPlaceholders, + ); + if !where_constraints.is_empty() { + err.span_help(where_constraints, where_msg); } - err.emit(); } + err.emit(); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index ce9b98848ba81..b00a5b697492a 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -1,5 +1,5 @@ use crate::astconv::{ - AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; use crate::errors::AssocTypeBindingNotAllowed; @@ -16,395 +16,361 @@ use rustc_span::{symbol::kw, MultiSpan, Span}; use smallvec::SmallVec; -impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - /// Report an error that a generic argument did not match the generic parameter that was - /// expected. - fn generic_arg_mismatch_err( - sess: &Session, - arg: &GenericArg<'_>, - kind: &'static str, - possible_ordering_error: bool, - help: Option<&str>, - ) { - let mut err = struct_span_err!( - sess, - arg.span(), - E0747, - "{} provided when a {} was expected", - arg.descr(), - kind, - ); - - let unordered = sess.features_untracked().const_generics; - let kind_ord = match kind { - "lifetime" => ParamKindOrd::Lifetime, - "type" => ParamKindOrd::Type, - "constant" => ParamKindOrd::Const { unordered }, - // It's more concise to match on the string representation, though it means - // the match is non-exhaustive. - _ => bug!("invalid generic parameter kind {}", kind), - }; - - if let ParamKindOrd::Const { .. } = kind_ord { - if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg { - err.help("const arguments cannot yet be inferred with `_`"); - } +/// Report an error that a generic argument did not match the generic parameter that was +/// expected. +fn generic_arg_mismatch_err( + sess: &Session, + arg: &GenericArg<'_>, + kind: &'static str, + possible_ordering_error: bool, + help: Option<&str>, +) { + let mut err = struct_span_err!( + sess, + arg.span(), + E0747, + "{} provided when a {} was expected", + arg.descr(), + kind, + ); + + let unordered = sess.features_untracked().const_generics; + let kind_ord = match kind { + "lifetime" => ParamKindOrd::Lifetime, + "type" => ParamKindOrd::Type, + "constant" => ParamKindOrd::Const { unordered }, + // It's more concise to match on the string representation, though it means + // the match is non-exhaustive. + _ => bug!("invalid generic parameter kind {}", kind), + }; + + if let ParamKindOrd::Const { .. } = kind_ord { + if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg { + err.help("const arguments cannot yet be inferred with `_`"); } + } - let arg_ord = match arg { - GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, - GenericArg::Type(_) => ParamKindOrd::Type, - GenericArg::Const(_) => ParamKindOrd::Const { unordered }, - }; + let arg_ord = match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const { unordered }, + }; + + if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })) + && matches!(kind_ord, ParamKindOrd::Const { .. }) + { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + err.multipart_suggestion( + "if this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } - if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })) - && matches!(kind_ord, ParamKindOrd::Const { .. }) - { - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - err.multipart_suggestion( - "if this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); + // This note is only true when generic parameters are strictly ordered by their kind. + if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { + let (first, last) = + if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; + err.note(&format!("{} arguments must be provided before {} arguments", first, last)); + if let Some(help) = help { + err.help(help); } + } - // This note is only true when generic parameters are strictly ordered by their kind. - if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { - let (first, last) = - if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; - err.note(&format!("{} arguments must be provided before {} arguments", first, last)); - if let Some(help) = help { - err.help(help); - } - } + err.emit(); +} - err.emit(); +/// Creates the relevant generic argument substitutions +/// corresponding to a set of generic parameters. This is a +/// rather complex function. Let us try to explain the role +/// of each of its parameters: +/// +/// To start, we are given the `def_id` of the thing we are +/// creating the substitutions for, and a partial set of +/// substitutions `parent_substs`. In general, the substitutions +/// for an item begin with substitutions for all the "parents" of +/// that item -- e.g., for a method it might include the +/// parameters from the impl. +/// +/// Therefore, the method begins by walking down these parents, +/// starting with the outermost parent and proceed inwards until +/// it reaches `def_id`. For each parent `P`, it will check `parent_substs` +/// first to see if the parent's substitutions are listed in there. If so, +/// we can append those and move on. Otherwise, it invokes the +/// three callback functions: +/// +/// - `args_for_def_id`: given the `DefId` `P`, supplies back the +/// generic arguments that were given to that parent from within +/// the path; so e.g., if you have `::Bar`, the `DefId` +/// might refer to the trait `Foo`, and the arguments might be +/// `[T]`. The boolean value indicates whether to infer values +/// for arguments whose values were not explicitly provided. +/// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`, +/// instantiate a `GenericArg`. +/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then +/// creates a suitable inference variable. +pub fn create_substs_for_generic_args<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + parent_substs: &[subst::GenericArg<'tcx>], + has_self: bool, + self_ty: Option>, + arg_count: GenericArgCountResult, + ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, +) -> SubstsRef<'tcx> { + // Collect the segments of the path; we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). + let mut parent_defs = tcx.generics_of(def_id); + let count = parent_defs.count(); + let mut stack = vec![(def_id, parent_defs)]; + while let Some(def_id) = parent_defs.parent { + parent_defs = tcx.generics_of(def_id); + stack.push((def_id, parent_defs)); } - /// Creates the relevant generic argument substitutions - /// corresponding to a set of generic parameters. This is a - /// rather complex function. Let us try to explain the role - /// of each of its parameters: - /// - /// To start, we are given the `def_id` of the thing we are - /// creating the substitutions for, and a partial set of - /// substitutions `parent_substs`. In general, the substitutions - /// for an item begin with substitutions for all the "parents" of - /// that item -- e.g., for a method it might include the - /// parameters from the impl. - /// - /// Therefore, the method begins by walking down these parents, - /// starting with the outermost parent and proceed inwards until - /// it reaches `def_id`. For each parent `P`, it will check `parent_substs` - /// first to see if the parent's substitutions are listed in there. If so, - /// we can append those and move on. Otherwise, it invokes the - /// three callback functions: - /// - /// - `args_for_def_id`: given the `DefId` `P`, supplies back the - /// generic arguments that were given to that parent from within - /// the path; so e.g., if you have `::Bar`, the `DefId` - /// might refer to the trait `Foo`, and the arguments might be - /// `[T]`. The boolean value indicates whether to infer values - /// for arguments whose values were not explicitly provided. - /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`, - /// instantiate a `GenericArg`. - /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then - /// creates a suitable inference variable. - pub fn create_substs_for_generic_args<'a>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - parent_substs: &[subst::GenericArg<'tcx>], - has_self: bool, - self_ty: Option>, - arg_count: GenericArgCountResult, - ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, - ) -> SubstsRef<'tcx> { - // Collect the segments of the path; we need to substitute arguments - // for parameters throughout the entire path (wherever there are - // generic parameters). - let mut parent_defs = tcx.generics_of(def_id); - let count = parent_defs.count(); - let mut stack = vec![(def_id, parent_defs)]; - while let Some(def_id) = parent_defs.parent { - parent_defs = tcx.generics_of(def_id); - stack.push((def_id, parent_defs)); + // We manually build up the substitution, rather than using convenience + // methods in `subst.rs`, so that we can iterate over the arguments and + // parameters in lock-step linearly, instead of trying to match each pair. + let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); + // Iterate over each segment of the path. + while let Some((def_id, defs)) = stack.pop() { + let mut params = defs.params.iter().peekable(); + + // If we have already computed substitutions for parents, we can use those directly. + while let Some(¶m) = params.peek() { + if let Some(&kind) = parent_substs.get(param.index as usize) { + substs.push(kind); + params.next(); + } else { + break; + } } - // We manually build up the substitution, rather than using convenience - // methods in `subst.rs`, so that we can iterate over the arguments and - // parameters in lock-step linearly, instead of trying to match each pair. - let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); - // Iterate over each segment of the path. - while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter().peekable(); - - // If we have already computed substitutions for parents, we can use those directly. - while let Some(¶m) = params.peek() { - if let Some(&kind) = parent_substs.get(param.index as usize) { - substs.push(kind); - params.next(); - } else { - break; + // `Self` is handled first, unless it's been handled in `parent_substs`. + if has_self { + if let Some(¶m) = params.peek() { + if param.index == 0 { + if let GenericParamDefKind::Type { .. } = param.kind { + substs.push( + self_ty + .map(|ty| ty.into()) + .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), + ); + params.next(); + } } } + } - // `Self` is handled first, unless it's been handled in `parent_substs`. - if has_self { - if let Some(¶m) = params.peek() { - if param.index == 0 { - if let GenericParamDefKind::Type { .. } = param.kind { - substs.push( - self_ty - .map(|ty| ty.into()) - .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), - ); + // Check whether this segment takes generic arguments and the user has provided any. + let (generic_args, infer_args) = ctx.args_for_def_id(def_id); + + let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); + let mut args = args_iter.clone().peekable(); + + // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. + // If we later encounter a lifetime, we know that the arguments were provided in the + // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be + // inferred, so we can use it for diagnostics later. + let mut force_infer_lt = None; + + loop { + // We're going to iterate through the generic arguments that the user + // provided, matching them with the generic parameters we expect. + // Mismatches can occur as a result of elided lifetimes, or for malformed + // input. We try to handle both sensibly. + match (args.peek(), params.peek()) { + (Some(&arg), Some(¶m)) => { + match (arg, ¶m.kind, arg_count.explicit_late_bound) { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) + | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { + substs.push(ctx.provided_kind(param, arg)); + args.next(); params.next(); } - } - } - } - - // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_args) = ctx.args_for_def_id(def_id); - - let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); - let mut args = args_iter.clone().peekable(); - - // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. - // If we later encounter a lifetime, we know that the arguments were provided in the - // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be - // inferred, so we can use it for diagnostics later. - let mut force_infer_lt = None; - - loop { - // We're going to iterate through the generic arguments that the user - // provided, matching them with the generic parameters we expect. - // Mismatches can occur as a result of elided lifetimes, or for malformed - // input. We try to handle both sensibly. - match (args.peek(), params.peek()) { - (Some(&arg), Some(¶m)) => { - match (arg, ¶m.kind, arg_count.explicit_late_bound) { - (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) - | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { - substs.push(ctx.provided_kind(param, arg)); - args.next(); - params.next(); - } - ( - GenericArg::Type(_) | GenericArg::Const(_), - GenericParamDefKind::Lifetime, - _, - ) => { - // We expected a lifetime argument, but got a type or const - // argument. That means we're inferring the lifetimes. - substs.push(ctx.inferred_kind(None, param, infer_args)); - force_infer_lt = Some(arg); - params.next(); - } - (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { - // We've come across a lifetime when we expected something else in - // the presence of explicit late bounds. This is most likely - // due to the presence of the explicit bound so we're just going to - // ignore it. - args.next(); - } - (_, kind, _) => { - // We expected one kind of parameter, but the user provided - // another. This is an error. However, if we already know that - // the arguments don't match up with the parameters, we won't issue - // an additional error, as the user already knows what's wrong. - if arg_count.correct.is_ok() - && arg_count.explicit_late_bound == ExplicitLateBound::No - { - // We're going to iterate over the parameters to sort them out, and - // show that order to the user as a possible order for the parameters - let mut param_types_present = defs - .params - .clone() - .into_iter() - .map(|param| { - ( - match param.kind { - GenericParamDefKind::Lifetime => { - ParamKindOrd::Lifetime - } - GenericParamDefKind::Type { .. } => { - ParamKindOrd::Type - } - GenericParamDefKind::Const => { - ParamKindOrd::Const { - unordered: tcx - .features() - .const_generics, - } - } + ( + GenericArg::Type(_) | GenericArg::Const(_), + GenericParamDefKind::Lifetime, + _, + ) => { + // We expected a lifetime argument, but got a type or const + // argument. That means we're inferring the lifetimes. + substs.push(ctx.inferred_kind(None, param, infer_args)); + force_infer_lt = Some(arg); + params.next(); + } + (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { + // We've come across a lifetime when we expected something else in + // the presence of explicit late bounds. This is most likely + // due to the presence of the explicit bound so we're just going to + // ignore it. + args.next(); + } + (_, kind, _) => { + // We expected one kind of parameter, but the user provided + // another. This is an error. However, if we already know that + // the arguments don't match up with the parameters, we won't issue + // an additional error, as the user already knows what's wrong. + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { + // We're going to iterate over the parameters to sort them out, and + // show that order to the user as a possible order for the parameters + let mut param_types_present = defs + .params + .clone() + .into_iter() + .map(|param| { + ( + match param.kind { + GenericParamDefKind::Lifetime => { + ParamKindOrd::Lifetime + } + GenericParamDefKind::Type { .. } => { + ParamKindOrd::Type + } + GenericParamDefKind::Const => ParamKindOrd::Const { + unordered: tcx.features().const_generics, }, - param, - ) - }) - .collect::>(); - param_types_present.sort_by_key(|(ord, _)| *ord); - let (mut param_types_present, ordered_params): ( - Vec, - Vec, - ) = param_types_present.into_iter().unzip(); - param_types_present.dedup(); - - Self::generic_arg_mismatch_err( - tcx.sess, - arg, - kind.descr(), - !args_iter.clone().is_sorted_by_key(|arg| match arg { - GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, - GenericArg::Type(_) => ParamKindOrd::Type, - GenericArg::Const(_) => ParamKindOrd::Const { - unordered: tcx.features().const_generics, }, - }), - Some(&format!( - "reorder the arguments: {}: `<{}>`", - param_types_present - .into_iter() - .map(|ord| format!("{}s", ord.to_string())) - .collect::>() - .join(", then "), - ordered_params - .into_iter() - .filter_map(|param| { - if param.name == kw::SelfUpper { - None - } else { - Some(param.name.to_string()) - } - }) - .collect::>() - .join(", ") - )), - ); - } - - // We've reported the error, but we want to make sure that this - // problem doesn't bubble down and create additional, irrelevant - // errors. In this case, we're simply going to ignore the argument - // and any following arguments. The rest of the parameters will be - // inferred. - while args.next().is_some() {} + param, + ) + }) + .collect::>(); + param_types_present.sort_by_key(|(ord, _)| *ord); + let (mut param_types_present, ordered_params): ( + Vec, + Vec, + ) = param_types_present.into_iter().unzip(); + param_types_present.dedup(); + + generic_arg_mismatch_err( + tcx.sess, + arg, + kind.descr(), + !args_iter.clone().is_sorted_by_key(|arg| match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const { + unordered: tcx.features().const_generics, + }, + }), + Some(&format!( + "reorder the arguments: {}: `<{}>`", + param_types_present + .into_iter() + .map(|ord| format!("{}s", ord.to_string())) + .collect::>() + .join(", then "), + ordered_params + .into_iter() + .filter_map(|param| { + if param.name == kw::SelfUpper { + None + } else { + Some(param.name.to_string()) + } + }) + .collect::>() + .join(", ") + )), + ); } - } - } - (Some(&arg), None) => { - // We should never be able to reach this point with well-formed input. - // There are three situations in which we can encounter this issue. - // - // 1. The number of arguments is incorrect. In this case, an error - // will already have been emitted, and we can ignore it. - // 2. There are late-bound lifetime parameters present, yet the - // lifetime arguments have also been explicitly specified by the - // user. - // 3. We've inferred some lifetimes, which have been provided later (i.e. - // after a type or const). We want to throw an error in this case. - - if arg_count.correct.is_ok() - && arg_count.explicit_late_bound == ExplicitLateBound::No - { - let kind = arg.descr(); - assert_eq!(kind, "lifetime"); - let provided = - force_infer_lt.expect("lifetimes ought to have been inferred"); - Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None); + // We've reported the error, but we want to make sure that this + // problem doesn't bubble down and create additional, irrelevant + // errors. In this case, we're simply going to ignore the argument + // and any following arguments. The rest of the parameters will be + // inferred. + while args.next().is_some() {} } - - break; } + } - (None, Some(¶m)) => { - // If there are fewer arguments than parameters, it means - // we're inferring the remaining arguments. - substs.push(ctx.inferred_kind(Some(&substs), param, infer_args)); - params.next(); + (Some(&arg), None) => { + // We should never be able to reach this point with well-formed input. + // There are three situations in which we can encounter this issue. + // + // 1. The number of arguments is incorrect. In this case, an error + // will already have been emitted, and we can ignore it. + // 2. There are late-bound lifetime parameters present, yet the + // lifetime arguments have also been explicitly specified by the + // user. + // 3. We've inferred some lifetimes, which have been provided later (i.e. + // after a type or const). We want to throw an error in this case. + + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { + let kind = arg.descr(); + assert_eq!(kind, "lifetime"); + let provided = + force_infer_lt.expect("lifetimes ought to have been inferred"); + generic_arg_mismatch_err(tcx.sess, provided, kind, false, None); } - (None, None) => break, + break; + } + + (None, Some(¶m)) => { + // If there are fewer arguments than parameters, it means + // we're inferring the remaining arguments. + substs.push(ctx.inferred_kind(Some(&substs), param, infer_args)); + params.next(); } + + (None, None) => break, } } - - tcx.intern_substs(&substs) } - /// Checks that the correct number of generic arguments have been provided. - /// Used specifically for function calls. - pub fn check_generic_arg_count_for_call( - tcx: TyCtxt<'_>, - span: Span, - def: &ty::Generics, - seg: &hir::PathSegment<'_>, - is_method_call: bool, - ) -> GenericArgCountResult { - let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); - Self::check_generic_arg_count( - tcx, - span, - def, - seg.args.unwrap_or(&hir::GenericArgs::none()), - if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value }, - def.parent.is_none() && def.has_self, // `has_self` - seg.infer_args || suppress_mismatch, // `infer_args` - ) - } + tcx.intern_substs(&substs) +} - /// Checks that the correct number of generic arguments have been provided. - /// This is used both for datatypes and function calls. - pub(crate) fn check_generic_arg_count( - tcx: TyCtxt<'_>, - span: Span, - def: &ty::Generics, - args: &hir::GenericArgs<'_>, - position: GenericArgPosition, - has_self: bool, - infer_args: bool, - ) -> GenericArgCountResult { - // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. - // that lifetimes will proceed types. So it suffices to check the number of each generic - // arguments in order to validate them with respect to the generic parameters. - let param_counts = def.own_counts(); - let named_type_param_count = param_counts.types - has_self as usize; - let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; - - let mut defaults: ty::GenericParamCount = Default::default(); - for param in &def.params { - match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type { has_default, .. } => { - defaults.types += has_default as usize - } - GenericParamDefKind::Const => { - // FIXME(const_generics_defaults) - } - }; - } +/// Checks that the correct number of generic arguments have been provided. +/// This is used both for datatypes and function calls. +pub(crate) fn check_generic_arg_count( + tcx: TyCtxt<'_>, + span: Span, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, + has_self: bool, + infer_args: bool, +) -> GenericArgCountResult { + // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. + // that lifetimes will proceed types. So it suffices to check the number of each generic + // arguments in order to validate them with respect to the generic parameters. + let param_counts = def.own_counts(); + let named_type_param_count = param_counts.types - has_self as usize; + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + let mut defaults: ty::GenericParamCount = Default::default(); + for param in &def.params { + match param.kind { + GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Type { has_default, .. } => defaults.types += has_default as usize, + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + } + }; + } - if position != GenericArgPosition::Type && !args.bindings.is_empty() { - AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); - } + if position != GenericArgPosition::Type && !args.bindings.is_empty() { + prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + } - let explicit_late_bound = - Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); + let explicit_late_bound = prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); - let check_kind_count = |kind, - required, - permitted, - provided, - offset, - unexpected_spans: &mut Vec, - silent| { + let check_kind_count = + |kind, required, permitted, provided, offset, unexpected_spans: &mut Vec, silent| { debug!( "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", kind, required, permitted, provided, offset @@ -471,143 +437,136 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { false }; - let mut unexpected_spans = vec![]; - - let lifetime_count_correct = check_kind_count( - "lifetime", - if infer_lifetimes { 0 } else { param_counts.lifetimes }, - param_counts.lifetimes, - arg_counts.lifetimes, - 0, - &mut unexpected_spans, - explicit_late_bound == ExplicitLateBound::Yes, - ); - - let kind_str = if param_counts.consts + arg_counts.consts == 0 { - "type" - } else if named_type_param_count + arg_counts.types == 0 { - "const" + let mut unexpected_spans = vec![]; + + let lifetime_count_correct = check_kind_count( + "lifetime", + if infer_lifetimes { 0 } else { param_counts.lifetimes }, + param_counts.lifetimes, + arg_counts.lifetimes, + 0, + &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, + ); + + let kind_str = if param_counts.consts + arg_counts.consts == 0 { + "type" + } else if named_type_param_count + arg_counts.types == 0 { + "const" + } else { + "generic" + }; + + let arg_count_correct = check_kind_count( + kind_str, + if infer_args { 0 } else { param_counts.consts + named_type_param_count - defaults.types }, + param_counts.consts + named_type_param_count, + arg_counts.consts + arg_counts.types, + arg_counts.lifetimes, + &mut unexpected_spans, + false, + ); + + GenericArgCountResult { + explicit_late_bound, + correct: if lifetime_count_correct && arg_count_correct { + Ok(()) } else { - "generic" - }; - - let arg_count_correct = check_kind_count( - kind_str, - if infer_args { - 0 - } else { - param_counts.consts + named_type_param_count - defaults.types - }, - param_counts.consts + named_type_param_count, - arg_counts.consts + arg_counts.types, - arg_counts.lifetimes, - &mut unexpected_spans, - false, - ); - - GenericArgCountResult { - explicit_late_bound, - correct: if lifetime_count_correct && arg_count_correct { - Ok(()) - } else { - Err(GenericArgCountMismatch { - reported: Some(ErrorReported), - invalid_args: unexpected_spans, - }) - }, - } + Err(GenericArgCountMismatch { + reported: Some(ErrorReported), + invalid_args: unexpected_spans, + }) + }, } +} - /// Report error if there is an explicit type parameter when using `impl Trait`. - pub(crate) fn check_impl_trait( - tcx: TyCtxt<'_>, - seg: &hir::PathSegment<'_>, - generics: &ty::Generics, - ) -> bool { - let explicit = !seg.infer_args; - let impl_trait = generics.params.iter().any(|param| { - matches!(param.kind, ty::GenericParamDefKind::Type { - synthetic: - Some( - hir::SyntheticTyParamKind::ImplTrait - | hir::SyntheticTyParamKind::FromAttr, - ), - .. +/// Report error if there is an explicit type parameter when using `impl Trait`. +pub(crate) fn check_impl_trait( + tcx: TyCtxt<'_>, + seg: &hir::PathSegment<'_>, + generics: &ty::Generics, +) -> bool { + let explicit = !seg.infer_args; + let impl_trait = generics.params.iter().any(|param| { + matches!(param.kind, ty::GenericParamDefKind::Type { + synthetic: + Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + }) + }); + + if explicit && impl_trait { + let spans = seg + .generic_args() + .args + .iter() + .filter_map(|arg| match arg { + GenericArg::Type(_) | GenericArg::Const(_) => Some(arg.span()), + _ => None, }) - }); - - if explicit && impl_trait { - let spans = seg - .generic_args() - .args - .iter() - .filter_map(|arg| match arg { - GenericArg::Type(_) | GenericArg::Const(_) => Some(arg.span()), - _ => None, - }) - .collect::>(); - - let mut err = struct_span_err! { - tcx.sess, - spans.clone(), - E0632, - "cannot provide explicit generic arguments when `impl Trait` is \ - used in argument position" - }; - - for span in spans { - err.span_label(span, "explicit generic argument not allowed"); - } + .collect::>(); + + let mut err = struct_span_err! { + tcx.sess, + spans.clone(), + E0632, + "cannot provide explicit generic arguments when `impl Trait` is \ + used in argument position" + }; - err.emit(); + for span in spans { + err.span_label(span, "explicit generic argument not allowed"); } - impl_trait + err.emit(); } - /// Emits an error regarding forbidden type binding associations - pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { - tcx.sess.emit_err(AssocTypeBindingNotAllowed { span }); - } + impl_trait +} - /// Prohibits explicit lifetime arguments if late-bound lifetime parameters - /// are present. This is used both for datatypes and function calls. - pub(crate) fn prohibit_explicit_late_bound_lifetimes( - tcx: TyCtxt<'_>, - def: &ty::Generics, - args: &hir::GenericArgs<'_>, - position: GenericArgPosition, - ) -> ExplicitLateBound { - let param_counts = def.own_counts(); - let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; - - if infer_lifetimes { - ExplicitLateBound::No - } else if let Some(span_late) = def.has_late_bound_regions { - let msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note = "the late bound lifetime parameter is introduced here"; - let span = args.args[0].span(); - if position == GenericArgPosition::Value - && arg_counts.lifetimes != param_counts.lifetimes - { - let mut err = tcx.sess.struct_span_err(span, msg); - err.span_note(span_late, note); - err.emit(); - } else { - let mut multispan = MultiSpan::from_span(span); - multispan.push_span_label(span_late, note.to_string()); - tcx.struct_span_lint_hir( - LATE_BOUND_LIFETIME_ARGUMENTS, - args.args[0].id(), - multispan, - |lint| lint.build(msg).emit(), - ); - } - ExplicitLateBound::Yes +/// Emits an error regarding forbidden type binding associations +pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { + tcx.sess.emit_err(AssocTypeBindingNotAllowed { span }); +} + +/// Prohibits explicit lifetime arguments if late-bound lifetime parameters +/// are present. This is used both for datatypes and function calls. +pub(crate) fn prohibit_explicit_late_bound_lifetimes( + tcx: TyCtxt<'_>, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, +) -> ExplicitLateBound { + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + if infer_lifetimes { + ExplicitLateBound::No + } else if let Some(span_late) = def.has_late_bound_regions { + let msg = "cannot specify lifetime arguments explicitly \ + if late bound lifetime parameters are present"; + let note = "the late bound lifetime parameter is introduced here"; + let span = args.args[0].span(); + if position == GenericArgPosition::Value && arg_counts.lifetimes != param_counts.lifetimes { + let mut err = tcx.sess.struct_span_err(span, msg); + err.span_note(span_late, note); + err.emit(); } else { - ExplicitLateBound::No + let mut multispan = MultiSpan::from_span(span); + multispan.push_span_label(span_late, note.to_string()); + tcx.struct_span_lint_hir( + LATE_BOUND_LIFETIME_ARGUMENTS, + args.args[0].id(), + multispan, + |lint| lint.build(msg).emit(), + ); } + ExplicitLateBound::Yes + } else { + ExplicitLateBound::No } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 9a2210e4f0e80..ac3d25447a6e4 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -3,7 +3,7 @@ //! instance of `AstConv`. mod errors; -mod generics; +pub(crate) mod generics; use crate::bounds::Bounds; use crate::collect::PlaceholderHirTyCollector; @@ -182,2187 +182,2199 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { ) -> subst::GenericArg<'tcx>; } -impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - pub fn ast_region_to_region( - &self, - lifetime: &hir::Lifetime, - def: Option<&ty::GenericParamDef>, - ) -> ty::Region<'tcx> { - let tcx = self.tcx(); - let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); - - let r = match tcx.named_region(lifetime.hir_id) { - Some(rl::Region::Static) => tcx.lifetimes.re_static, - - Some(rl::Region::LateBound(debruijn, id, _)) => { - let name = lifetime_name(id.expect_local()); - let br = ty::BoundRegion { kind: ty::BrNamed(id, name) }; - tcx.mk_region(ty::ReLateBound(debruijn, br)) - } +pub fn ast_region_to_region<'tcx>( + astconv: &impl AstConv<'tcx>, + lifetime: &hir::Lifetime, + def: Option<&ty::GenericParamDef>, +) -> ty::Region<'tcx> { + let tcx = astconv.tcx(); + let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); + + let r = match tcx.named_region(lifetime.hir_id) { + Some(rl::Region::Static) => tcx.lifetimes.re_static, + + Some(rl::Region::LateBound(debruijn, id, _)) => { + let name = lifetime_name(id.expect_local()); + let br = ty::BoundRegion { kind: ty::BrNamed(id, name) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) + } - Some(rl::Region::LateBoundAnon(debruijn, index)) => { - let br = ty::BoundRegion { kind: ty::BrAnon(index) }; - tcx.mk_region(ty::ReLateBound(debruijn, br)) - } + Some(rl::Region::LateBoundAnon(debruijn, index)) => { + let br = ty::BoundRegion { kind: ty::BrAnon(index) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) + } - Some(rl::Region::EarlyBound(index, id, _)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) - } + Some(rl::Region::EarlyBound(index, id, _)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) + } - Some(rl::Region::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope, - bound_region: ty::BrNamed(id, name), - })) + Some(rl::Region::Free(scope, id)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReFree(ty::FreeRegion { scope, bound_region: ty::BrNamed(id, name) })) - // (*) -- not late-bound, won't change - } + // (*) -- not late-bound, won't change + } - None => { - self.re_infer(def, lifetime.span).unwrap_or_else(|| { - // This indicates an illegal lifetime - // elision. `resolve_lifetime` should have - // reported an error in this case -- but if - // not, let's error out. - tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); + None => { + astconv.re_infer(def, lifetime.span).unwrap_or_else(|| { + // This indicates an illegal lifetime + // elision. `resolve_lifetime` should have + // reported an error in this case -- but if + // not, let's error out. + tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); + + // Supply some dummy value. We don't have an + // `re_error`, annoyingly, so use `'static`. + tcx.lifetimes.re_static + }) + } + }; - // Supply some dummy value. We don't have an - // `re_error`, annoyingly, so use `'static`. - tcx.lifetimes.re_static - }) - } - }; + debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); + r +} - r +/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, +/// returns an appropriate set of substitutions for this particular reference to `I`. +pub fn ast_path_substs_for_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + def_id: DefId, + item_segment: &hir::PathSegment<'_>, +) -> SubstsRef<'tcx> { + let (substs, assoc_bindings, _) = create_substs_for_ast_path( + astconv, + span, + def_id, + &[], + item_segment.generic_args(), + item_segment.infer_args, + None, + ); + + if let Some(b) = assoc_bindings.first() { + generics::prohibit_assoc_ty_binding(astconv.tcx(), b.span); } - /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, - /// returns an appropriate set of substitutions for this particular reference to `I`. - pub fn ast_path_substs_for_ty( - &self, - span: Span, - def_id: DefId, - item_segment: &hir::PathSegment<'_>, - ) -> SubstsRef<'tcx> { - let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( - span, - def_id, - &[], - item_segment.generic_args(), - item_segment.infer_args, - None, - ); + substs +} - if let Some(b) = assoc_bindings.first() { - Self::prohibit_assoc_ty_binding(self.tcx(), b.span); +/// Given the type/lifetime/const arguments provided to some path (along with +/// an implicit `Self`, if this is a trait reference), returns the complete +/// set of substitutions. This may involve applying defaulted type parameters. +/// Also returns back constraints on associated types. +/// +/// Example: +/// +/// ``` +/// T: std::ops::Index +/// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 +/// ``` +/// +/// 1. The `self_ty` here would refer to the type `T`. +/// 2. The path in question is the path to the trait `std::ops::Index`, +/// which will have been resolved to a `def_id` +/// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type +/// parameters are returned in the `SubstsRef`, the associated type bindings like +/// `Output = u32` are returned in the `Vec` result. +/// +/// Note that the type listing given here is *exactly* what the user provided. +/// +/// For (generic) associated types +/// +/// ``` +/// as Iterable>::Iter::<'a> +/// ``` +/// +/// We have the parent substs are the substs for the parent trait: +/// `[Vec, u8]` and `generic_args` are the arguments for the associated +/// type itself: `['a]`. The returned `SubstsRef` concatenates these two +/// lists: `[Vec, u8, 'a]`. +fn create_substs_for_ast_path<'a, 'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + def_id: DefId, + parent_substs: &[subst::GenericArg<'tcx>], + generic_args: &'a hir::GenericArgs<'_>, + infer_args: bool, + self_ty: Option>, +) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { + // If the type is parameterized by this region, then replace this + // region with the current anon region binding (in other words, + // whatever & would get replaced with). + debug!( + "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ + generic_args={:?})", + def_id, self_ty, generic_args + ); + + let tcx = astconv.tcx(); + let generic_params = tcx.generics_of(def_id); + + if generic_params.has_self { + if generic_params.parent.is_some() { + // The parent is a trait so it should have at least one subst + // for the `Self` type. + assert!(!parent_substs.is_empty()) + } else { + // This item (presumably a trait) needs a self-type. + assert!(self_ty.is_some()); } + } else { + assert!(self_ty.is_none() && parent_substs.is_empty()); + } - substs + let arg_count = generics::check_generic_arg_count( + tcx, + span, + &generic_params, + &generic_args, + GenericArgPosition::Type, + self_ty.is_some(), + infer_args, + ); + + // Skip processing if type has no generic parameters. + // Traits always have `Self` as a generic parameter, which means they will not return early + // here and so associated type bindings will be handled regardless of whether there are any + // non-`Self` generic parameters. + if generic_params.params.len() == 0 { + return (tcx.intern_substs(&[]), vec![], arg_count); } - /// Given the type/lifetime/const arguments provided to some path (along with - /// an implicit `Self`, if this is a trait reference), returns the complete - /// set of substitutions. This may involve applying defaulted type parameters. - /// Also returns back constraints on associated types. - /// - /// Example: - /// - /// ``` - /// T: std::ops::Index - /// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 - /// ``` - /// - /// 1. The `self_ty` here would refer to the type `T`. - /// 2. The path in question is the path to the trait `std::ops::Index`, - /// which will have been resolved to a `def_id` - /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type - /// parameters are returned in the `SubstsRef`, the associated type bindings like - /// `Output = u32` are returned in the `Vec` result. - /// - /// Note that the type listing given here is *exactly* what the user provided. - /// - /// For (generic) associated types - /// - /// ``` - /// as Iterable>::Iter::<'a> - /// ``` - /// - /// We have the parent substs are the substs for the parent trait: - /// `[Vec, u8]` and `generic_args` are the arguments for the associated - /// type itself: `['a]`. The returned `SubstsRef` concatenates these two - /// lists: `[Vec, u8, 'a]`. - fn create_substs_for_ast_path<'a>( - &self, - span: Span, + let is_object = self_ty.map_or(false, |ty| ty == tcx.types.trait_object_dummy_self); + + struct SubstsForAstPathCtxt<'a, A> { + astconv: &'a A, def_id: DefId, - parent_substs: &[subst::GenericArg<'tcx>], - generic_args: &'a hir::GenericArgs<'_>, + generic_args: &'a GenericArgs<'a>, + span: Span, + missing_type_params: Vec, + inferred_params: Vec, infer_args: bool, - self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { - // If the type is parameterized by this region, then replace this - // region with the current anon region binding (in other words, - // whatever & would get replaced with). - debug!( - "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ - generic_args={:?})", - def_id, self_ty, generic_args - ); - - let tcx = self.tcx(); - let generic_params = tcx.generics_of(def_id); + is_object: bool, + } - if generic_params.has_self { - if generic_params.parent.is_some() { - // The parent is a trait so it should have at least one subst - // for the `Self` type. - assert!(!parent_substs.is_empty()) - } else { - // This item (presumably a trait) needs a self-type. - assert!(self_ty.is_some()); + impl<'tcx, 'a, A: AstConv<'tcx>> SubstsForAstPathCtxt<'a, A> { + fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { + let tcx = self.astconv.tcx(); + if let GenericParamDefKind::Type { has_default, .. } = param.kind { + if self.is_object && has_default { + let default_ty = tcx.at(self.span).type_of(param.def_id); + let self_param = tcx.types.self_param; + if default_ty.walk().any(|arg| arg == self_param.into()) { + // There is no suitable inference default for a type parameter + // that references self, in an object type. + return true; + } + } } - } else { - assert!(self_ty.is_none() && parent_substs.is_empty()); - } - - let arg_count = Self::check_generic_arg_count( - tcx, - span, - &generic_params, - &generic_args, - GenericArgPosition::Type, - self_ty.is_some(), - infer_args, - ); - // Skip processing if type has no generic parameters. - // Traits always have `Self` as a generic parameter, which means they will not return early - // here and so associated type bindings will be handled regardless of whether there are any - // non-`Self` generic parameters. - if generic_params.params.len() == 0 { - return (tcx.intern_substs(&[]), vec![], arg_count); + false } + } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - - struct SubstsForAstPathCtxt<'a, 'tcx> { - astconv: &'a (dyn AstConv<'tcx> + 'a), - def_id: DefId, - generic_args: &'a GenericArgs<'a>, - span: Span, - missing_type_params: Vec, - inferred_params: Vec, - infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false + impl<'a, 'tcx, A> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, A> + where + A: AstConv<'tcx>, + { + fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { + if did == self.def_id { + (Some(self.generic_args), self.infer_args) + } else { + // The last component of this tuple is unimportant. + (None, false) } } - impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { - fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { - if did == self.def_id { - (Some(self.generic_args), self.infer_args) - } else { - // The last component of this tuple is unimportant. - (None, false) + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + ast_region_to_region(self.astconv, <, Some(param)).into() } - } - - fn provided_kind( - &mut self, - param: &ty::GenericParamDef, - arg: &GenericArg<'_>, - ) -> subst::GenericArg<'tcx> { - let tcx = self.astconv.tcx(); - match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.astconv.ast_region_to_region(<, Some(param)).into() - } - (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { - if has_default { - tcx.check_optional_stability( - param.def_id, - Some(arg.id()), - arg.span(), - |_, _| { - // Default generic parameters may not be marked - // with stability attributes, i.e. when the - // default parameter was defined at the same time - // as the rest of the type. As such, we ignore missing - // stability attributes. - }, - ) - } - if let (hir::TyKind::Infer, false) = - (&ty.kind, self.astconv.allow_ty_infer()) - { - self.inferred_params.push(ty.span); - tcx.ty_error().into() - } else { - self.astconv.ast_ty_to_ty(&ty).into() - } - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - ty::Const::from_opt_const_arg_anon_const( - tcx, - ty::WithOptConstParam { - did: tcx.hir().local_def_id(ct.value.hir_id), - const_param_did: Some(param.def_id), + (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. }, ) - .into() } - _ => unreachable!(), + if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) { + self.inferred_params.push(ty.span); + tcx.ty_error().into() + } else { + ast_ty_to_ty(self.astconv, &ty).into() + } } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + ty::Const::from_opt_const_arg_anon_const( + tcx, + ty::WithOptConstParam { + did: tcx.hir().local_def_id(ct.value.hir_id), + const_param_did: Some(param.def_id), + }, + ) + .into() + } + _ => unreachable!(), } + } - fn inferred_kind( - &mut self, - substs: Option<&[subst::GenericArg<'tcx>]>, - param: &ty::GenericParamDef, - infer_args: bool, - ) -> subst::GenericArg<'tcx> { - let tcx = self.astconv.tcx(); - match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name.to_string()); - tcx.ty_error().into() - } else { - // This is a default type parameter. - self.astconv - .normalize_ty( - self.span, - tcx.at(self.span).type_of(param.def_id).subst_spanned( - tcx, - substs.unwrap(), - Some(self.span), - ), - ) - .into() - } - } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() - } else { - // We've already errored above about the mismatch. + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); + match param.kind { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // No type parameter provided, but a default exists. + + // If we are converting an object type, then the + // `Self` parameter is unknown. However, some of the + // other type parameters may reference `Self` in their + // defaults. This will lead to an ICE if we are not + // careful! + if self.default_needs_object_self(param) { + self.missing_type_params.push(param.name.to_string()); tcx.ty_error().into() - } - } - GenericParamDefKind::Const => { - let ty = tcx.at(self.span).type_of(param.def_id); - // FIXME(const_generics_defaults) - if infer_args { - // No const parameters were provided, we can infer all. - self.astconv.ct_infer(ty, Some(param), self.span).into() } else { - // We've already errored above about the mismatch. - tcx.const_error(ty).into() + // This is a default type parameter. + self.astconv + .normalize_ty( + self.span, + tcx.at(self.span).type_of(param.def_id).subst_spanned( + tcx, + substs.unwrap(), + Some(self.span), + ), + ) + .into() } + } else if infer_args { + // No type parameters were provided, we can infer all. + let param = + if !self.default_needs_object_self(param) { Some(param) } else { None }; + self.astconv.ty_infer(param, self.span).into() + } else { + // We've already errored above about the mismatch. + tcx.ty_error().into() + } + } + GenericParamDefKind::Const => { + let ty = tcx.at(self.span).type_of(param.def_id); + // FIXME(const_generics:defaults) + if infer_args { + // No const parameters were provided, we can infer all. + self.astconv.ct_infer(ty, Some(param), self.span).into() + } else { + // We've already errored above about the mismatch. + tcx.const_error(ty).into() } } } } - - let mut substs_ctx = SubstsForAstPathCtxt { - astconv: self, - def_id, - span, - generic_args, - missing_type_params: vec![], - inferred_params: vec![], - infer_args, - is_object, - }; - let substs = Self::create_substs_for_generic_args( - tcx, - def_id, - parent_substs, - self_ty.is_some(), - self_ty, - arg_count.clone(), - &mut substs_ctx, - ); - - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - - // Convert associated-type bindings or constraints into a separate vector. - // Example: Given this: - // - // T: Iterator - // - // The `T` is passed in as a self-type; the `Item = u32` is - // not a "type parameter" of the `Iterator` trait, but rather - // a restriction on `::Item`, so it is passed - // back separately. - let assoc_bindings = generic_args - .bindings - .iter() - .map(|binding| { - let kind = match binding.kind { - hir::TypeBindingKind::Equality { ref ty } => { - ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) - } - hir::TypeBindingKind::Constraint { ref bounds } => { - ConvertedBindingKind::Constraint(bounds) - } - }; - ConvertedBinding { item_name: binding.ident, kind, span: binding.span } - }) - .collect(); - - debug!( - "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", - generic_params, self_ty, substs - ); - - (substs, assoc_bindings, arg_count) } - crate fn create_substs_for_associated_item( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - parent_substs: SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { - if tcx.generics_of(item_def_id).params.is_empty() { - self.prohibit_generics(slice::from_ref(item_segment)); + let mut substs_ctx = SubstsForAstPathCtxt { + astconv, + def_id, + span, + generic_args, + missing_type_params: vec![], + inferred_params: vec![], + infer_args, + is_object, + }; + let substs = generics::create_substs_for_generic_args( + tcx, + def_id, + parent_substs, + self_ty.is_some(), + self_ty, + arg_count.clone(), + &mut substs_ctx, + ); + + errors::complain_about_missing_type_params( + astconv, + substs_ctx.missing_type_params, + def_id, + span, + generic_args.args.is_empty(), + ); + + // Convert associated-type bindings or constraints into a separate vector. + // Example: Given this: + // + // T: Iterator + // + // The `T` is passed in as a self-type; the `Item = u32` is + // not a "type parameter" of the `Iterator` trait, but rather + // a restriction on `::Item`, so it is passed + // back separately. + let assoc_bindings = generic_args + .bindings + .iter() + .map(|binding| { + let kind = match binding.kind { + hir::TypeBindingKind::Equality { ref ty } => { + ConvertedBindingKind::Equality(ast_ty_to_ty(astconv, ty)) + } + hir::TypeBindingKind::Constraint { ref bounds } => { + ConvertedBindingKind::Constraint(bounds) + } + }; + ConvertedBinding { item_name: binding.ident, kind, span: binding.span } + }) + .collect(); - parent_substs - } else { - self.create_substs_for_ast_path( - span, - item_def_id, - parent_substs, - item_segment.generic_args(), - item_segment.infer_args, - None, - ) - .0 - } - } + debug!( + "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", + generic_params, self_ty, substs + ); - /// Instantiates the path for the given trait reference, assuming that it's - /// bound to a valid trait type. Returns the `DefId` of the defining trait. - /// The type _cannot_ be a type other than a trait type. - /// - /// If the `projections` argument is `None`, then assoc type bindings like `Foo` - /// are disallowed. Otherwise, they are pushed onto the vector given. - pub fn instantiate_mono_trait_ref( - &self, - trait_ref: &hir::TraitRef<'_>, - self_ty: Ty<'tcx>, - ) -> ty::TraitRef<'tcx> { - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - - self.ast_path_to_mono_trait_ref( - trait_ref.path.span, - trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), - self_ty, - trait_ref.path.segments.last().unwrap(), + (substs, assoc_bindings, arg_count) +} + +crate fn create_substs_for_associated_item<'tcx>( + astconv: &impl AstConv<'tcx>, + tcx: TyCtxt<'tcx>, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + parent_substs: SubstsRef<'tcx>, +) -> SubstsRef<'tcx> { + if tcx.generics_of(item_def_id).params.is_empty() { + prohibit_generics(astconv, slice::from_ref(item_segment)); + + parent_substs + } else { + create_substs_for_ast_path( + astconv, + span, + item_def_id, + parent_substs, + item_segment.generic_args(), + item_segment.infer_args, + None, ) + .0 } +} - /// The given trait-ref must actually be a trait. - pub(super) fn instantiate_poly_trait_ref_inner( - &self, - trait_ref: &hir::TraitRef<'_>, - span: Span, - constness: Constness, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - ) -> GenericArgCountResult { - let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); - - debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); - - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - - let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( - trait_ref.path.span, - trait_def_id, - self_ty, - trait_ref.path.segments.last().unwrap(), - ); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - - bounds.trait_bounds.push((poly_trait_ref, span, constness)); - - let mut dup_bindings = FxHashMap::default(); - for binding in &assoc_bindings { - // Specify type to assert that error was already reported in `Err` case. - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - trait_ref.hir_ref_id, - poly_trait_ref, - binding, - bounds, - speculative, - &mut dup_bindings, - binding.span, - ); - // Okay to ignore `Err` because of `ErrorReported` (see above). - } - - debug!( - "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", - trait_ref, bounds, poly_trait_ref - ); - - arg_count - } +/// Instantiates the path for the given trait reference, assuming that it's +/// bound to a valid trait type. Returns the `DefId` of the defining trait. +/// The type _cannot_ be a type other than a trait type. +/// +/// If the `projections` argument is `None`, then assoc type bindings like `Foo` +/// are disallowed. Otherwise, they are pushed onto the vector given. +pub fn instantiate_mono_trait_ref<'tcx>( + astconv: &impl AstConv<'tcx>, + trait_ref: &hir::TraitRef<'_>, + self_ty: Ty<'tcx>, +) -> ty::TraitRef<'tcx> { + prohibit_generics(astconv, trait_ref.path.segments.split_last().unwrap().1); + + ast_path_to_mono_trait_ref( + astconv, + trait_ref.path.span, + trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), + self_ty, + trait_ref.path.segments.last().unwrap(), + ) +} - /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct - /// a full trait reference. The resulting trait reference is returned. This may also generate - /// auxiliary bounds, which are added to `bounds`. - /// - /// Example: - /// - /// ``` - /// poly_trait_ref = Iterator - /// self_ty = Foo - /// ``` - /// - /// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. - /// - /// **A note on binders:** against our usual convention, there is an implied bounder around - /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. - /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` - /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be - /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, - /// however. - pub fn instantiate_poly_trait_ref( - &self, - poly_trait_ref: &hir::PolyTraitRef<'_>, - constness: Constness, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - ) -> GenericArgCountResult { - self.instantiate_poly_trait_ref_inner( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - self_ty, +/// The given trait-ref must actually be a trait. +pub(super) fn instantiate_poly_trait_ref_inner<'tcx>( + astconv: &impl AstConv<'tcx>, + trait_ref: &hir::TraitRef<'_>, + span: Span, + constness: Constness, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + speculative: bool, +) -> GenericArgCountResult { + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + + debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); + + prohibit_generics(astconv, trait_ref.path.segments.split_last().unwrap().1); + + let (substs, assoc_bindings, arg_count) = create_substs_for_ast_trait_ref( + astconv, + trait_ref.path.span, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap(), + ); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + + bounds.trait_bounds.push((poly_trait_ref, span, constness)); + + let mut dup_bindings = FxHashMap::default(); + for binding in &assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = add_predicates_for_ast_type_binding( + astconv, + trait_ref.hir_ref_id, + poly_trait_ref, + binding, bounds, - false, - ) - } - - pub fn instantiate_lang_item_trait_ref( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - args: &GenericArgs<'_>, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - ) { - let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); - - let (substs, assoc_bindings, _) = - self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty)); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); - - let mut dup_bindings = FxHashMap::default(); - for binding in assoc_bindings { - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - hir_id, - poly_trait_ref, - &binding, - bounds, - false, - &mut dup_bindings, - span, - ); - } + speculative, + &mut dup_bindings, + binding.span, + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). } - fn ast_path_to_mono_trait_ref( - &self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment<'_>, - ) -> ty::TraitRef<'tcx> { - let (substs, assoc_bindings, _) = - self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); - if let Some(b) = assoc_bindings.first() { - Self::prohibit_assoc_ty_binding(self.tcx(), b.span); - } - ty::TraitRef::new(trait_def_id, substs) - } + debug!( + "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", + trait_ref, bounds, poly_trait_ref + ); - fn create_substs_for_ast_trait_ref<'a>( - &self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); + arg_count +} - self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); +/// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct +/// a full trait reference. The resulting trait reference is returned. This may also generate +/// auxiliary bounds, which are added to `bounds`. +/// +/// Example: +/// +/// ``` +/// poly_trait_ref = Iterator +/// self_ty = Foo +/// ``` +/// +/// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. +/// +/// **A note on binders:** against our usual convention, there is an implied bounder around +/// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. +/// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` +/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be +/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, +/// however. +pub fn instantiate_poly_trait_ref<'tcx>( + astconv: &impl AstConv<'tcx>, + poly_trait_ref: &hir::PolyTraitRef<'_>, + constness: Constness, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, +) -> GenericArgCountResult { + instantiate_poly_trait_ref_inner( + astconv, + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, + self_ty, + bounds, + false, + ) +} - self.create_substs_for_ast_path( +pub fn instantiate_lang_item_trait_ref<'tcx>( + astconv: &impl AstConv<'tcx>, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + args: &GenericArgs<'_>, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, +) { + let trait_def_id = astconv.tcx().require_lang_item(lang_item, Some(span)); + + let (substs, assoc_bindings, _) = + create_substs_for_ast_path(astconv, span, trait_def_id, &[], args, false, Some(self_ty)); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); + + let mut dup_bindings = FxHashMap::default(); + for binding in assoc_bindings { + let _: Result<_, ErrorReported> = add_predicates_for_ast_type_binding( + astconv, + hir_id, + poly_trait_ref, + &binding, + bounds, + false, + &mut dup_bindings, span, - trait_def_id, - &[], - trait_segment.generic_args(), - trait_segment.infer_args, - Some(self_ty), - ) + ); } +} - fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.tcx() - .associated_items(trait_def_id) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id) - .is_some() +fn ast_path_to_mono_trait_ref<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &hir::PathSegment<'_>, +) -> ty::TraitRef<'tcx> { + let (substs, assoc_bindings, _) = + create_substs_for_ast_trait_ref(astconv, span, trait_def_id, self_ty, trait_segment); + if let Some(b) = assoc_bindings.first() { + generics::prohibit_assoc_ty_binding(astconv.tcx(), b.span); } + ty::TraitRef::new(trait_def_id, substs) +} - // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { - let tcx = self.tcx(); +fn create_substs_for_ast_trait_ref<'a, 'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &'a hir::PathSegment<'a>, +) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); + + errors::complain_about_internal_fn_trait(astconv, span, trait_def_id, trait_segment); + + create_substs_for_ast_path( + astconv, + span, + trait_def_id, + &[], + trait_segment.generic_args(), + trait_segment.infer_args, + Some(self_ty), + ) +} - // Try to find an unbound in bounds. - let mut unbound = None; - for ab in ast_bounds { - if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); - } +fn trait_defines_associated_type_named<'tcx>( + astconv: &impl AstConv<'tcx>, + trait_def_id: DefId, + assoc_name: Ident, +) -> bool { + let tcx = astconv.tcx(); + tcx.associated_items(trait_def_id) + .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id) + .is_some() +} + +// Returns `true` if a bounds list includes `?Sized`. +pub fn is_unsized<'tcx>( + astconv: &impl AstConv<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + span: Span, +) -> bool { + let tcx = astconv.tcx(); + + // Try to find an unbound in bounds. + let mut unbound = None; + for ab in ast_bounds { + if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + unbound = Some(&ptr.trait_ref); + } else { + tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); } } + } - let kind_id = tcx.lang_items().require(LangItem::Sized); - match unbound { - Some(tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - } + let kind_id = tcx.lang_items().require(LangItem::Sized); + match unbound { + Some(tpb) => { + // FIXME(#8559) currently requires the unbound to be built-in. + if let Ok(kind_id) = kind_id { + if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { + tcx.sess.span_warn( + span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default; only `?Sized` is supported", + ); } } - _ if kind_id.is_ok() => { - return false; - } - // No lang item for `Sized`, so we can't add it as a bound. - None => {} } - - true + _ if kind_id.is_ok() => { + return false; + } + // No lang item for `Sized`, so we can't add it as a bound. + None => {} } - /// This helper takes a *converted* parameter type (`param_ty`) - /// and an *unconverted* list of bounds: - /// - /// ```text - /// fn foo - /// ^ ^^^^^ `ast_bounds` parameter, in HIR form - /// | - /// `param_ty`, in ty form - /// ``` - /// - /// It adds these `ast_bounds` into the `bounds` structure. - /// - /// **A note on binders:** there is an implied binder around - /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` - /// for more details. - fn add_bounds( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - bounds: &mut Bounds<'tcx>, - ) { - let constness = self.default_constness_for_trait_bounds(); - for ast_bound in ast_bounds { - match *ast_bound { - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - self.instantiate_poly_trait_ref(b, constness, param_ty, bounds); - } - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - self.instantiate_poly_trait_ref(b, Constness::NotConst, param_ty, bounds); - } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self - .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, - ), - hir::GenericBound::Outlives(ref l) => bounds - .region_bounds - .push((ty::Binder::bind(self.ast_region_to_region(l, None)), l.span)), + true +} + +/// This helper takes a *converted* parameter type (`param_ty`) +/// and an *unconverted* list of bounds: +/// +/// ```text +/// fn foo +/// ^ ^^^^^ `ast_bounds` parameter, in HIR form +/// | +/// `param_ty`, in ty form +/// ``` +/// +/// It adds these `ast_bounds` into the `bounds` structure. +/// +/// **A note on binders:** there is an implied binder around +/// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` +/// for more details. +fn add_bounds<'tcx>( + astconv: &impl AstConv<'tcx>, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + bounds: &mut Bounds<'tcx>, +) { + let constness = astconv.default_constness_for_trait_bounds(); + for ast_bound in ast_bounds { + match *ast_bound { + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { + instantiate_poly_trait_ref(astconv, b, constness, param_ty, bounds); } + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { + instantiate_poly_trait_ref(astconv, b, Constness::NotConst, param_ty, bounds); + } + hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} + hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + instantiate_lang_item_trait_ref( + astconv, lang_item, span, hir_id, args, param_ty, bounds, + ) + } + hir::GenericBound::Outlives(ref l) => bounds + .region_bounds + .push((ty::Binder::bind(ast_region_to_region(astconv, l, None)), l.span)), } } +} - /// Translates a list of bounds from the HIR into the `Bounds` data structure. - /// The self-type for the bounds is given by `param_ty`. - /// - /// Example: - /// - /// ``` - /// fn foo() { } - /// ^ ^^^^^^^^^ ast_bounds - /// param_ty - /// ``` - /// - /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be - /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the - /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. - /// - /// `span` should be the declaration size of the parameter. - pub fn compute_bounds( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, - ) -> Bounds<'tcx> { - let mut bounds = Bounds::default(); +/// Translates a list of bounds from the HIR into the `Bounds` data structure. +/// The self-type for the bounds is given by `param_ty`. +/// +/// Example: +/// +/// ``` +/// fn foo() { } +/// ^ ^^^^^^^^^ ast_bounds +/// param_ty +/// ``` +/// +/// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be +/// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the +/// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. +/// +/// `span` should be the declaration size of the parameter. +pub fn compute_bounds<'tcx>( + astconv: &impl AstConv<'tcx>, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, +) -> Bounds<'tcx> { + let mut bounds = Bounds::default(); - self.add_bounds(param_ty, ast_bounds, &mut bounds); - bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); + add_bounds(astconv, param_ty, ast_bounds, &mut bounds); + bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); - bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } - } else { - None - }; + bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { + if !is_unsized(astconv, ast_bounds, span) { Some(span) } else { None } + } else { + None + }; - bounds - } + bounds +} - /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates - /// onto `bounds`. - /// - /// **A note on binders:** given something like `T: for<'a> Iterator`, the - /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* - /// the binder (e.g., `&'a u32`) and hence may reference bound regions. - fn add_predicates_for_ast_type_binding( - &self, - hir_ref_id: hir::HirId, - trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'_, 'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - dup_bindings: &mut FxHashMap, - path_span: Span, - ) -> Result<(), ErrorReported> { - let tcx = self.tcx(); - - if !speculative { - // Given something like `U: SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait: SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B: SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. +/// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates +/// onto `bounds`. +/// +/// **A note on binders:** given something like `T: for<'a> Iterator`, the +/// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* +/// the binder (e.g., `&'a u32`) and hence may reference bound regions. +fn add_predicates_for_ast_type_binding<'tcx>( + astconv: &impl AstConv<'tcx>, + hir_ref_id: hir::HirId, + trait_ref: ty::PolyTraitRef<'tcx>, + binding: &ConvertedBinding<'_, 'tcx>, + bounds: &mut Bounds<'tcx>, + speculative: bool, + dup_bindings: &mut FxHashMap, + path_span: Span, +) -> Result<(), ErrorReported> { + let tcx = astconv.tcx(); + + if !speculative { + // Given something like `U: SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait: SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B: SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref. These are not well-formed. - // - // Example: - // - // for<'a> ::Item = &'a str // <-- 'a is bad - // for<'a> >::Output = &'a str // <-- 'a is ok - if let ConvertedBindingKind::Equality(ty) = binding.kind { - let late_bound_in_trait_ref = - tcx.collect_constrained_late_bound_regions(&trait_ref); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); - - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1 Fn(&i32, &i32) -> &'a i32>(F); - // ---- ---- ^^^^^^^ - self.validate_late_bound_regions( - late_bound_in_trait_ref, - late_bound_in_ty, - |br_name| { - struct_span_err!( - tcx.sess, - binding.span, - E0582, - "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.item_name, - br_name - ) - }, - ); - } + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + if let ConvertedBindingKind::Equality(ty) = binding.kind { + let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); + let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + validate_late_bound_regions(late_bound_in_trait_ref, late_bound_in_ty, |br_name| { + struct_span_err!( + tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + binding.item_name, + br_name + ) + }); } + } - let candidate = - if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { - // Simple case: X is defined in the current trait. - trait_ref - } else { - // Otherwise, we have to walk through the supertraits to find - // those that do. - self.one_bound_for_assoc_type( - || traits::supertraits(tcx, trait_ref), - || trait_ref.print_only_trait_path().to_string(), - binding.item_name, - path_span, - || match binding.kind { - ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), - _ => None, - }, - )? - }; + let candidate = + if trait_defines_associated_type_named(astconv, trait_ref.def_id(), binding.item_name) { + // Simple case: X is defined in the current trait. + trait_ref + } else { + // Otherwise, we have to walk through the supertraits to find + // those that do. + one_bound_for_assoc_type( + astconv, + || traits::supertraits(tcx, trait_ref), + || trait_ref.print_only_trait_path().to_string(), + binding.item_name, + path_span, + || match binding.kind { + ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + _ => None, + }, + )? + }; + + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. + let assoc_ty = tcx + .associated_items(candidate.def_id()) + .filter_by_name_unhygienic(assoc_ident.name) + .find(|i| i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident) + .expect("missing associated type"); - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let assoc_ty = tcx - .associated_items(candidate.def_id()) - .filter_by_name_unhygienic(assoc_ident.name) - .find(|i| { - i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident + if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { + tcx.sess + .struct_span_err( + binding.span, + &format!("associated type `{}` is private", binding.item_name), + ) + .span_label(binding.span, "private associated type") + .emit(); + } + tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span); + + if !speculative { + dup_bindings + .entry(assoc_ty.def_id) + .and_modify(|prev_span| { + tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified { + span: binding.span, + prev_span: *prev_span, + item_name: binding.item_name, + def_path: tcx.def_path_str(assoc_ty.container.id()), + }); }) - .expect("missing associated type"); + .or_insert(binding.span); + } - if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { - tcx.sess - .struct_span_err( - binding.span, - &format!("associated type `{}` is private", binding.item_name), - ) - .span_label(binding.span, "private associated type") - .emit(); + match binding.kind { + ConvertedBindingKind::Equality(ref ty) => { + // "Desugar" a constraint like `T: Iterator` this to + // the "projection predicate" for: + // + // `::Item = u32` + bounds.projection_bounds.push(( + candidate.map_bound(|trait_ref| ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + binding.item_name, + ), + ty, + }), + binding.span, + )); } - tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span); - - if !speculative { - dup_bindings - .entry(assoc_ty.def_id) - .and_modify(|prev_span| { - self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified { - span: binding.span, - prev_span: *prev_span, - item_name: binding.item_name, - def_path: tcx.def_path_str(assoc_ty.container.id()), - }); - }) - .or_insert(binding.span); + ConvertedBindingKind::Constraint(ast_bounds) => { + // "Desugar" a constraint like `T: Iterator` to + // + // `::Item: Debug` + // + // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` + // parameter to have a skipped binder. + let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); + add_bounds(astconv, param_ty, ast_bounds, bounds); } + } + Ok(()) +} - match binding.kind { - ConvertedBindingKind::Equality(ref ty) => { - // "Desugar" a constraint like `T: Iterator` this to - // the "projection predicate" for: - // - // `::Item = u32` - bounds.projection_bounds.push(( - candidate.map_bound(|trait_ref| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - binding.item_name, - ), - ty, - }), - binding.span, - )); - } - ConvertedBindingKind::Constraint(ast_bounds) => { - // "Desugar" a constraint like `T: Iterator` to - // - // `::Item: Debug` - // - // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` - // parameter to have a skipped binder. - let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); - self.add_bounds(param_ty, ast_bounds, bounds); - } +fn ast_path_to_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + did: DefId, + item_segment: &hir::PathSegment<'_>, +) -> Ty<'tcx> { + let tcx = astconv.tcx(); + let substs = ast_path_substs_for_ty(astconv, span, did, item_segment); + astconv.normalize_ty(span, tcx.at(span).type_of(did).subst(tcx, substs)) +} + +fn conv_object_ty_poly_trait_ref<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + trait_bounds: &[hir::PolyTraitRef<'_>], + lifetime: &hir::Lifetime, + borrowed: bool, +) -> Ty<'tcx> { + let tcx = astconv.tcx(); + + let mut bounds = Bounds::default(); + let mut potential_assoc_types = Vec::new(); + let dummy_self = tcx.types.trait_object_dummy_self; + for trait_bound in trait_bounds.iter().rev() { + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = instantiate_poly_trait_ref( + astconv, + trait_bound, + Constness::NotConst, + dummy_self, + &mut bounds, + ) { + potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); } - Ok(()) } - fn ast_path_to_ty( - &self, - span: Span, - did: DefId, - item_segment: &hir::PathSegment<'_>, - ) -> Ty<'tcx> { - let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) + // Expand trait aliases recursively and check that only one regular (non-auto) trait + // is used and no 'maybe' bounds are used. + let expanded_traits = + traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); + let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = + expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + if regular_traits.len() > 1 { + let first_trait = ®ular_traits[0]; + let additional_trait = ®ular_traits[1]; + let mut err = struct_span_err!( + tcx.sess, + additional_trait.bottom().1, + E0225, + "only auto traits can be used as additional traits in a trait object" + ); + additional_trait.label_with_exp_info( + &mut err, + "additional non-auto trait", + "additional use", + ); + first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.help(&format!( + "consider creating a new trait with all of these as super-traits and using that \ + trait here instead: `trait NewTrait: {} {{}}`", + regular_traits + .iter() + .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .collect::>() + .join(" + "), + )); + err.note( + "auto-traits like `Send` and `Sync` are traits that have special properties; \ + for more information on them, visit \ + ", + ); + err.emit(); } - fn conv_object_ty_poly_trait_ref( - &self, - span: Span, - trait_bounds: &[hir::PolyTraitRef<'_>], - lifetime: &hir::Lifetime, - borrowed: bool, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - let mut bounds = Bounds::default(); - let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in trait_bounds.iter().rev() { - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.instantiate_poly_trait_ref( - trait_bound, - Constness::NotConst, - dummy_self, - &mut bounds, - ) { - potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = - expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); - if regular_traits.len() > 1 { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; - let mut err = struct_span_err!( - tcx.sess, - additional_trait.bottom().1, - E0225, - "only auto traits can be used as additional traits in a trait object" - ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); - err.help(&format!( - "consider creating a new trait with all of these as super-traits and using that \ - trait here instead: `trait NewTrait: {} {{}}`", - regular_traits - .iter() - .map(|t| t.trait_ref().print_only_trait_path().to_string()) - .collect::>() - .join(" + "), - )); - err.note( - "auto-traits like `Send` and `Sync` are traits that have special properties; \ - for more information on them, visit \ - ", - ); - err.emit(); - } + if regular_traits.is_empty() && auto_traits.is_empty() { + tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span }); + return tcx.ty_error(); + } - if regular_traits.is_empty() && auto_traits.is_empty() { - tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span }); + // Check that there are no gross object safety violations; + // most importantly, that the supertraits don't contain `Self`, + // to avoid ICEs. + for item in ®ular_traits { + let object_safety_violations = + astconv_object_safety_violations(tcx, item.trait_ref().def_id()); + if !object_safety_violations.is_empty() { + report_object_safety_error( + tcx, + span, + item.trait_ref().def_id(), + &object_safety_violations[..], + ) + .emit(); return tcx.ty_error(); } + } - // Check that there are no gross object safety violations; - // most importantly, that the supertraits don't contain `Self`, - // to avoid ICEs. - for item in ®ular_traits { - let object_safety_violations = - astconv_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - report_object_safety_error( - tcx, - span, - item.trait_ref().def_id(), - &object_safety_violations[..], - ) - .emit(); - return tcx.ty_error(); - } - } - - // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types: FxHashMap> = FxHashMap::default(); + // Use a `BTreeSet` to keep output in a more consistent order. + let mut associated_types: FxHashMap> = FxHashMap::default(); - let regular_traits_refs_spans = bounds - .trait_bounds - .into_iter() - .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + let regular_traits_refs_spans = bounds + .trait_bounds + .into_iter() + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); - for (base_trait_ref, span, constness) in regular_traits_refs_spans { - assert_eq!(constness, Constness::NotConst); + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, Constness::NotConst); - for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) { - debug!( - "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", - obligation.predicate - ); + for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) { + debug!( + "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", + obligation.predicate + ); - let bound_predicate = obligation.predicate.bound_atom(); - match bound_predicate.skip_binder() { - ty::PredicateAtom::Trait(pred, _) => { - let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( - tcx.associated_items(pred.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .map(|item| item.def_id), - ); - } - ty::PredicateAtom::Projection(pred) => { - let pred = bound_predicate.rebind(pred); - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = - pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classicaly useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> ::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ Ï„ → dyn MyTrait::MyOutput`. - // - // Instead, we force the user to write - // `dyn MyTrait`, which is uglier but works. See - // the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - bounds.projection_bounds.push((pred, span)); - } + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { + ty::PredicateAtom::Trait(pred, _) => { + let pred = bound_predicate.rebind(pred); + associated_types.entry(span).or_default().extend( + tcx.associated_items(pred.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id), + ); + } + ty::PredicateAtom::Projection(pred) => { + let pred = bound_predicate.rebind(pred); + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = + pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classicaly useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> ::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ Ï„ → dyn MyTrait::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + bounds.projection_bounds.push((pred, span)); } - _ => (), } + _ => (), } } + } - for (projection_bound, _) in &bounds.projection_bounds { - for def_ids in associated_types.values_mut() { - def_ids.remove(&projection_bound.projection_def_id()); - } + for (projection_bound, _) in &bounds.projection_bounds { + for def_ids in associated_types.values_mut() { + def_ids.remove(&projection_bound.projection_def_id()); } + } - self.complain_about_missing_associated_types( - associated_types, - potential_assoc_types, - trait_bounds, - ); - - // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as - // `dyn Trait + Send`. - auto_traits.sort_by_key(|i| i.trait_ref().def_id()); - auto_traits.dedup_by_key(|i| i.trait_ref().def_id()); - debug!("regular_traits: {:?}", regular_traits); - debug!("auto_traits: {:?}", auto_traits); - - // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - // removing the dummy `Self` type (`trait_object_dummy_self`). - let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), - ); + errors::complain_about_missing_associated_types( + astconv, + associated_types, + potential_assoc_types, + trait_bounds, + ); + + // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as + // `dyn Trait + Send`. + auto_traits.sort_by_key(|i| i.trait_ref().def_id()); + auto_traits.dedup_by_key(|i| i.trait_ref().def_id()); + debug!("regular_traits: {:?}", regular_traits); + debug!("auto_traits: {:?}", auto_traits); + + // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by + // removing the dummy `Self` type (`trait_object_dummy_self`). + let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { + if trait_ref.self_ty() != dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, + // which picks up non-supertraits where clauses - but also, the object safety + // completely ignores trait aliases, which could be object safety hazards. We + // `delay_span_bug` here to avoid an ICE in stable even when the feature is + // disabled. (#66420) + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref,), + ); + } + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }; + + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. + let existential_trait_refs = + regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { + bound.map_bound(|b| { + let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); + ty::ExistentialProjection { + ty: b.ty, + item_def_id: b.projection_ty.item_def_id, + substs: trait_ref.substs, } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }; - - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = - regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); - let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|b| { - let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); - ty::ExistentialProjection { - ty: b.ty, - item_def_id: b.projection_ty.item_def_id, - substs: trait_ref.substs, - } - }) - }); - - let regular_trait_predicates = existential_trait_refs.map(|trait_ref| { - trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref)) - }); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) - }); - let mut v = regular_trait_predicates - .chain(auto_trait_predicates) - .chain( - existential_projections - .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))), - ) - .collect::>(); - v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - v.dedup(); - let existential_predicates = tcx.mk_poly_existential_predicates(v.into_iter()); - - // Use explicitly-specified region bound. - let region_bound = if !lifetime.is_elided() { - self.ast_region_to_region(lifetime, None) - } else { - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if tcx.named_region(lifetime.hir_id).is_some() { - self.ast_region_to_region(lifetime, None) - } else { - self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( - tcx.sess, - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug(); - } else { - err.emit(); - } - tcx.lifetimes.re_static - }) - } - }) - }; - debug!("region_bound: {:?}", region_bound); + }) + }); + + let regular_trait_predicates = existential_trait_refs.map(|trait_ref| { + trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref)) + }); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); + let mut v = regular_trait_predicates + .chain(auto_trait_predicates) + .chain( + existential_projections + .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))), + ) + .collect::>(); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + v.dedup(); + let existential_predicates = tcx.mk_poly_existential_predicates(v.into_iter()); + + // Use explicitly-specified region bound. + let region_bound = if !lifetime.is_elided() { + ast_region_to_region(astconv, lifetime, None) + } else { + compute_object_lifetime_bound(astconv, span, existential_predicates).unwrap_or_else(|| { + if tcx.named_region(lifetime.hir_id).is_some() { + ast_region_to_region(astconv, lifetime, None) + } else { + astconv.re_infer(None, span).unwrap_or_else(|| { + let mut err = struct_span_err!( + tcx.sess, + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ); + if borrowed { + // We will have already emitted an error E0106 complaining about a + // missing named lifetime in `&dyn Trait`, so we elide this one. + err.delay_as_bug(); + } else { + err.emit(); + } + tcx.lifetimes.re_static + }) + } + }) + }; + debug!("region_bound: {:?}", region_bound); - let ty = tcx.mk_dynamic(existential_predicates, region_bound); - debug!("trait_object_type: {:?}", ty); - ty - } + let ty = tcx.mk_dynamic(existential_predicates, region_bound); + debug!("trait_object_type: {:?}", ty); + ty +} - fn report_ambiguous_associated_type( - &self, - span: Span, - type_str: &str, - trait_str: &str, - name: Symbol, +fn report_ambiguous_associated_type<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + type_str: &str, + trait_str: &str, + name: Symbol, +) { + let tcx = astconv.tcx(); + let mut err = struct_span_err!(tcx.sess, span, E0223, "ambiguous associated type"); + if let (Some(_), Ok(snippet)) = ( + tcx.sess.confused_type_with_std_module.borrow().get(&span), + tcx.sess.source_map().span_to_snippet(span), ) { - let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); - if let (Some(_), Ok(snippet)) = ( - self.tcx().sess.confused_type_with_std_module.borrow().get(&span), - self.tcx().sess.source_map().span_to_snippet(span), - ) { - err.span_suggestion( - span, - "you are looking for the module in `std`, not the primitive type", - format!("std::{}", snippet), - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders, - ); - } - err.emit(); + err.span_suggestion( + span, + "you are looking for the module in `std`, not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", type_str, trait_str, name), + Applicability::HasPlaceholders, + ); } + err.emit(); +} - // Search for a bound on a type parameter which includes the associated item - // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter - // This function will fail if there are no suitable bounds or there is - // any ambiguity. - fn find_bound_for_assoc_item( - &self, - ty_param_def_id: LocalDefId, - assoc_name: Ident, - span: Span, - ) -> Result, ErrorReported> { - let tcx = self.tcx(); +// Search for a bound on a type parameter which includes the associated item +// given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter +// This function will fail if there are no suitable bounds or there is +// any ambiguity. +fn find_bound_for_assoc_item<'tcx>( + astconv: &impl AstConv<'tcx>, + ty_param_def_id: LocalDefId, + assoc_name: Ident, + span: Span, +) -> Result, ErrorReported> { + let tcx = astconv.tcx(); - debug!( - "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})", - ty_param_def_id, assoc_name, span, - ); + debug!( + "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})", + ty_param_def_id, assoc_name, span, + ); - let predicates = - &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; + let predicates = + &astconv.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; - debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); + debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); - let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id); - let param_name = tcx.hir().ty_param_name(param_hir_id); - self.one_bound_for_assoc_type( - || { - traits::transitive_bounds( - tcx, - predicates.iter().filter_map(|(p, _)| { - p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) - }), - ) - }, - || param_name.to_string(), - assoc_name, - span, - || None, - ) - } + let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id); + let param_name = tcx.hir().ty_param_name(param_hir_id); + one_bound_for_assoc_type( + astconv, + || { + traits::transitive_bounds( + tcx, + predicates.iter().filter_map(|(p, _)| { + p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) + }), + ) + }, + || param_name.to_string(), + assoc_name, + span, + || None, + ) +} - // Checks that `bounds` contains exactly one element and reports appropriate - // errors otherwise. - fn one_bound_for_assoc_type( - &self, - all_candidates: impl Fn() -> I, - ty_param_name: impl Fn() -> String, - assoc_name: Ident, - span: Span, - is_equality: impl Fn() -> Option, - ) -> Result, ErrorReported> - where - I: Iterator>, - { - let mut matching_candidates = all_candidates() - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name)); - - let bound = match matching_candidates.next() { - Some(bound) => bound, - None => { - self.complain_about_assoc_type_not_found( - all_candidates, - &ty_param_name(), - assoc_name, - span, - ); - return Err(ErrorReported); - } - }; +// Checks that `bounds` contains exactly one element and reports appropriate +// errors otherwise. +fn one_bound_for_assoc_type<'tcx, I>( + astconv: &impl AstConv<'tcx>, + all_candidates: impl Fn() -> I, + ty_param_name: impl Fn() -> String, + assoc_name: Ident, + span: Span, + is_equality: impl Fn() -> Option, +) -> Result, ErrorReported> +where + I: Iterator>, +{ + let mut matching_candidates = all_candidates() + .filter(|r| trait_defines_associated_type_named(astconv, r.def_id(), assoc_name)); + + let bound = match matching_candidates.next() { + Some(bound) => bound, + None => { + errors::complain_about_assoc_type_not_found( + astconv, + all_candidates, + &ty_param_name(), + assoc_name, + span, + ); + return Err(ErrorReported); + } + }; - debug!("one_bound_for_assoc_type: bound = {:?}", bound); + debug!("one_bound_for_assoc_type: bound = {:?}", bound); - if let Some(bound2) = matching_candidates.next() { - debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); + if let Some(bound2) = matching_candidates.next() { + debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); - let is_equality = is_equality(); - let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates); - let mut err = if is_equality.is_some() { - // More specific Error Index entry. - struct_span_err!( - self.tcx().sess, - span, - E0222, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name() - ) - } else { - struct_span_err!( - self.tcx().sess, - span, - E0221, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name() - ) - }; - err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); - - let mut where_bounds = vec![]; - for bound in bounds { - let bound_id = bound.def_id(); - let bound_span = self - .tcx() - .associated_items(bound_id) - .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id) - .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); - - if let Some(bound_span) = bound_span { - err.span_label( - bound_span, + let is_equality = is_equality(); + let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates); + let tcx = astconv.tcx(); + let mut err = if is_equality.is_some() { + // More specific Error Index entry. + struct_span_err!( + tcx.sess, + span, + E0222, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name() + ) + } else { + struct_span_err!( + tcx.sess, + span, + E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name() + ) + }; + err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); + + let mut where_bounds = vec![]; + for bound in bounds { + let bound_id = bound.def_id(); + let bound_span = tcx + .associated_items(bound_id) + .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, bound_id) + .and_then(|item| tcx.hir().span_if_local(item.def_id)); + + if let Some(bound_span) = bound_span { + err.span_label( + bound_span, + format!("ambiguous `{}` from `{}`", assoc_name, bound.print_only_trait_path(),), + ); + if let Some(constraint) = &is_equality { + where_bounds.push(format!( + " T: {trait}::{assoc} = {constraint}", + trait=bound.print_only_trait_path(), + assoc=assoc_name, + constraint=constraint, + )); + } else { + err.span_suggestion( + span, + "use fully qualified syntax to disambiguate", format!( - "ambiguous `{}` from `{}`", - assoc_name, + "<{} as {}>::{}", + ty_param_name(), bound.print_only_trait_path(), + assoc_name, ), + Applicability::MaybeIncorrect, ); - if let Some(constraint) = &is_equality { - where_bounds.push(format!( - " T: {trait}::{assoc} = {constraint}", - trait=bound.print_only_trait_path(), - assoc=assoc_name, - constraint=constraint, - )); - } else { - err.span_suggestion( - span, - "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::{}", - ty_param_name(), - bound.print_only_trait_path(), - assoc_name, - ), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note(&format!( - "associated type `{}` could derive from `{}`", - ty_param_name(), - bound.print_only_trait_path(), - )); } - } - if !where_bounds.is_empty() { - err.help(&format!( - "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {},\n{}", + } else { + err.note(&format!( + "associated type `{}` could derive from `{}`", ty_param_name(), - where_bounds.join(",\n"), + bound.print_only_trait_path(), )); } - err.emit(); - if !where_bounds.is_empty() { - return Err(ErrorReported); - } } - Ok(bound) - } - - // Create a type from a path to an associated type. - // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` - // and item_segment is the path segment for `D`. We return a type and a def for - // the whole path. - // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type - // parameter or `Self`. - pub fn associated_path_to_ty( - &self, - hir_ref_id: hir::HirId, - span: Span, - qself_ty: Ty<'tcx>, - qself_res: Res, - assoc_segment: &hir::PathSegment<'_>, - permit_variants: bool, - ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> { - let tcx = self.tcx(); - let assoc_ident = assoc_segment.ident; - - debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident); - - // Check if we have an enum variant. - let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind() { - if adt_def.is_enum() { - let variant_def = adt_def - .variants - .iter() - .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)); - if let Some(variant_def) = variant_def { - if permit_variants { - tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span); - self.prohibit_generics(slice::from_ref(assoc_segment)); - return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); - } else { - variant_resolution = Some(variant_def.def_id); - } - } - } + if !where_bounds.is_empty() { + err.help(&format!( + "consider introducing a new type parameter `T` and adding `where` constraints:\ + \n where\n T: {},\n{}", + ty_param_name(), + where_bounds.join(",\n"), + )); } + err.emit(); + if !where_bounds.is_empty() { + return Err(ErrorReported); + } + } + Ok(bound) +} - // Find the type of the associated item, and the trait where the associated - // item is declared. - let bound = match (&qself_ty.kind(), qself_res) { - (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { - // `Self` in an impl of a trait -- we have a concrete self type and a - // trait reference. - let trait_ref = match tcx.impl_trait_ref(impl_def_id) { - Some(trait_ref) => trait_ref, - None => { - // A cycle error occurred, most likely. - return Err(ErrorReported); - } - }; - - self.one_bound_for_assoc_type( - || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), - || "Self".to_string(), - assoc_ident, - span, - || None, - )? - } - ( - &ty::Param(_), - Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did), - ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?, - _ => { - if variant_resolution.is_some() { - // Variant in type position - let msg = format!("expected type, found variant `{}`", assoc_ident); - tcx.sess.span_err(span, &msg); - } else if qself_ty.is_enum() { - let mut err = struct_span_err!( - tcx.sess, - assoc_ident.span, - E0599, - "no variant named `{}` found for enum `{}`", - assoc_ident, - qself_ty, - ); - - let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(suggested_name) = find_best_match_for_name( - &adt_def - .variants - .iter() - .map(|variant| variant.ident.name) - .collect::>(), - assoc_ident.name, - None, - ) { - err.span_suggestion( - assoc_ident.span, - "there is a variant with a similar name", - suggested_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - assoc_ident.span, - format!("variant not found in `{}`", qself_ty), - ); - } - - if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { - let sp = tcx.sess.source_map().guess_head_span(sp); - err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); - } - - err.emit(); - } else if !qself_ty.references_error() { - // Don't print `TyErr` to the user. - self.report_ambiguous_associated_type( - span, - &qself_ty.to_string(), - "Trait", - assoc_ident.name, - ); +// Create a type from a path to an associated type. +// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` +// and item_segment is the path segment for `D`. We return a type and a def for +// the whole path. +// Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type +// parameter or `Self`. +pub fn associated_path_to_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + hir_ref_id: hir::HirId, + span: Span, + qself_ty: Ty<'tcx>, + qself_res: Res, + assoc_segment: &hir::PathSegment<'_>, + permit_variants: bool, +) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> { + let tcx = astconv.tcx(); + let assoc_ident = assoc_segment.ident; + + debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident); + + // Check if we have an enum variant. + let mut variant_resolution = None; + if let ty::Adt(adt_def, _) = qself_ty.kind() { + if adt_def.is_enum() { + let variant_def = adt_def + .variants + .iter() + .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)); + if let Some(variant_def) = variant_def { + if permit_variants { + tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span); + prohibit_generics(astconv, slice::from_ref(assoc_segment)); + return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); + } else { + variant_resolution = Some(variant_def.def_id); } - return Err(ErrorReported); } - }; + } + } - let trait_did = bound.def_id(); - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); - - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let item = tcx - .associated_items(trait_did) - .in_definition_order() - .find(|i| { - i.kind.namespace() == Namespace::TypeNS - && i.ident.normalize_to_macros_2_0() == assoc_ident - }) - .expect("missing associated type"); - - let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); - let ty = self.normalize_ty(span, ty); - - let kind = DefKind::AssocTy; - if !item.vis.is_accessible_from(def_scope, tcx) { - let kind = kind.descr(item.def_id); - let msg = format!("{} `{}` is private", kind, assoc_ident); - tcx.sess - .struct_span_err(span, &msg) - .span_label(span, &format!("private {}", kind)) - .emit(); + // Find the type of the associated item, and the trait where the associated + // item is declared. + let bound = match (&qself_ty.kind(), qself_res) { + (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { + // `Self` in an impl of a trait -- we have a concrete self type and a + // trait reference. + let trait_ref = match tcx.impl_trait_ref(impl_def_id) { + Some(trait_ref) => trait_ref, + None => { + // A cycle error occurred, most likely. + return Err(ErrorReported); + } + }; + + one_bound_for_assoc_type( + astconv, + || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), + || "Self".to_string(), + assoc_ident, + span, + || None, + )? } - tcx.check_stability(item.def_id, Some(hir_ref_id), span); - - if let Some(variant_def_id) = variant_resolution { - tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { - let mut err = lint.build("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - assoc_ident, - also, - kind.descr(def_id) + ( + &ty::Param(_), + Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did), + ) => find_bound_for_assoc_item(astconv, param_did.expect_local(), assoc_ident, span)?, + _ => { + if variant_resolution.is_some() { + // Variant in type position + let msg = format!("expected type, found variant `{}`", assoc_ident); + tcx.sess.span_err(span, &msg); + } else if qself_ty.is_enum() { + let mut err = struct_span_err!( + tcx.sess, + assoc_ident.span, + E0599, + "no variant named `{}` found for enum `{}`", + assoc_ident, + qself_ty, + ); + + let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); + if let Some(suggested_name) = find_best_match_for_name( + &adt_def + .variants + .iter() + .map(|variant| variant.ident.name) + .collect::>(), + assoc_ident.name, + None, + ) { + err.span_suggestion( + assoc_ident.span, + "there is a variant with a similar name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + assoc_ident.span, + format!("variant not found in `{}`", qself_ty), ); - err.span_note(tcx.def_span(def_id), ¬e_msg); - }; + } - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(kind, item.def_id, " also"); + if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { + let sp = tcx.sess.source_map().guess_head_span(sp); + err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); + } - err.span_suggestion( + err.emit(); + } else if !qself_ty.references_error() { + // Don't print `TyErr` to the user. + report_ambiguous_associated_type( + astconv, span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), - Applicability::MachineApplicable, + &qself_ty.to_string(), + "Trait", + assoc_ident.name, ); - - err.emit(); - }); + } + return Err(ErrorReported); } - Ok((ty, kind, item.def_id)) + }; + + let trait_did = bound.def_id(); + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. + let item = tcx + .associated_items(trait_did) + .in_definition_order() + .find(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident.normalize_to_macros_2_0() == assoc_ident + }) + .expect("missing associated type"); + + let ty = astconv.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); + let ty = astconv.normalize_ty(span, ty); + + let kind = DefKind::AssocTy; + if !item.vis.is_accessible_from(def_scope, tcx) { + let kind = kind.descr(item.def_id); + let msg = format!("{} `{}` is private", kind, assoc_ident); + tcx.sess.struct_span_err(span, &msg).span_label(span, &format!("private {}", kind)).emit(); } + tcx.check_stability(item.def_id, Some(hir_ref_id), span); + + if let Some(variant_def_id) = variant_resolution { + tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { + let mut err = lint.build("ambiguous associated item"); + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + assoc_ident, + also, + kind.descr(def_id) + ); + err.span_note(tcx.def_span(def_id), ¬e_msg); + }; - fn qpath_to_ty( - &self, - span: Span, - opt_self_ty: Option>, - item_def_id: DefId, - trait_segment: &hir::PathSegment<'_>, - item_segment: &hir::PathSegment<'_>, - ) -> Ty<'tcx> { - let tcx = self.tcx(); + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(kind, item.def_id, " also"); - let trait_def_id = tcx.parent(item_def_id).unwrap(); + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), + Applicability::MachineApplicable, + ); - debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); + err.emit(); + }); + } + Ok((ty, kind, item.def_id)) +} - let self_ty = if let Some(ty) = opt_self_ty { - ty - } else { - let path_str = tcx.def_path_str(trait_def_id); +fn qpath_to_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + opt_self_ty: Option>, + item_def_id: DefId, + trait_segment: &hir::PathSegment<'_>, + item_segment: &hir::PathSegment<'_>, +) -> Ty<'tcx> { + let tcx = astconv.tcx(); - let def_id = self.item_def_id(); + let trait_def_id = tcx.parent(item_def_id).unwrap(); - debug!("qpath_to_ty: self.item_def_id()={:?}", def_id); + debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); - let parent_def_id = def_id - .and_then(|def_id| { - def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) - }) - .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id()); + let self_ty = if let Some(ty) = opt_self_ty { + ty + } else { + let path_str = tcx.def_path_str(trait_def_id); - debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); + let def_id = astconv.item_def_id(); - // If the trait in segment is the same as the trait defining the item, - // use the `` syntax in the error. - let is_part_of_self_trait_constraints = def_id == Some(trait_def_id); - let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); + debug!("qpath_to_ty: self.item_def_id()={:?}", def_id); - let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - "Self" - } else { - "Type" - }; + let parent_def_id = def_id + .and_then(|def_id| { + def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + }) + .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id()); - self.report_ambiguous_associated_type( - span, - type_name, - &path_str, - item_segment.ident.name, - ); - return tcx.ty_error(); - }; + debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); - debug!("qpath_to_ty: self_type={:?}", self_ty); + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + let is_part_of_self_trait_constraints = def_id == Some(trait_def_id); + let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); - let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment); + let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + "Self" + } else { + "Type" + }; - let item_substs = self.create_substs_for_associated_item( - tcx, + report_ambiguous_associated_type( + astconv, span, - item_def_id, - item_segment, - trait_ref.substs, + type_name, + &path_str, + item_segment.ident.name, ); + return tcx.ty_error(); + }; - debug!("qpath_to_ty: trait_ref={:?}", trait_ref); + debug!("qpath_to_ty: self_type={:?}", self_ty); - self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs)) - } + let trait_ref = ast_path_to_mono_trait_ref(astconv, span, trait_def_id, self_ty, trait_segment); - pub fn prohibit_generics<'a, T: IntoIterator>>( - &self, - segments: T, - ) -> bool { - let mut has_err = false; - for segment in segments { - let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); - for arg in segment.generic_args().args { - let (span, kind) = match arg { - hir::GenericArg::Lifetime(lt) => { - if err_for_lt { - continue; - } - err_for_lt = true; - has_err = true; - (lt.span, "lifetime") + let item_substs = create_substs_for_associated_item( + astconv, + tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + debug!("qpath_to_ty: trait_ref={:?}", trait_ref); + + astconv.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs)) +} + +pub fn prohibit_generics<'a, 'tcx, T: IntoIterator>>( + astconv: &impl AstConv<'tcx>, + segments: T, +) -> bool { + let mut has_err = false; + for segment in segments { + let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); + for arg in segment.generic_args().args { + let (span, kind) = match arg { + hir::GenericArg::Lifetime(lt) => { + if err_for_lt { + continue; } - hir::GenericArg::Type(ty) => { - if err_for_ty { - continue; - } - err_for_ty = true; - has_err = true; - (ty.span, "type") + err_for_lt = true; + has_err = true; + (lt.span, "lifetime") + } + hir::GenericArg::Type(ty) => { + if err_for_ty { + continue; } - hir::GenericArg::Const(ct) => { - if err_for_ct { - continue; - } - err_for_ct = true; - has_err = true; - (ct.span, "const") + err_for_ty = true; + has_err = true; + (ty.span, "type") + } + hir::GenericArg::Const(ct) => { + if err_for_ct { + continue; } - }; - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0109, - "{} arguments are not allowed for this type", - kind, - ); - err.span_label(span, format!("{} argument not allowed", kind)); - err.emit(); - if err_for_lt && err_for_ty && err_for_ct { - break; + err_for_ct = true; + has_err = true; + (ct.span, "const") } + }; + let mut err = struct_span_err!( + astconv.tcx().sess, + span, + E0109, + "{} arguments are not allowed for this type", + kind, + ); + err.span_label(span, format!("{} argument not allowed", kind)); + err.emit(); + if err_for_lt && err_for_ty && err_for_ct { + break; } + } - // Only emit the first error to avoid overloading the user with error messages. - if let [binding, ..] = segment.generic_args().bindings { - has_err = true; - Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); - } + // Only emit the first error to avoid overloading the user with error messages. + if let [binding, ..] = segment.generic_args().bindings { + has_err = true; + generics::prohibit_assoc_ty_binding(astconv.tcx(), binding.span); } - has_err } + has_err +} - // FIXME(eddyb, varkor) handle type paths here too, not just value ones. - pub fn def_ids_for_value_path_segments( - &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option>, - kind: DefKind, - def_id: DefId, - ) -> Vec { - // We need to extract the type parameters supplied by the user in - // the path `path`. Due to the current setup, this is a bit of a - // tricky-process; the problem is that resolve only tells us the - // end-point of the path resolution, and not the intermediate steps. - // Luckily, we can (at least for now) deduce the intermediate steps - // just from the end-point. - // - // There are basically five cases to consider: - // - // 1. Reference to a constructor of a struct: - // - // struct Foo(...) - // - // In this case, the parameters are declared in the type space. - // - // 2. Reference to a constructor of an enum variant: - // - // enum E { Foo(...) } - // - // In this case, the parameters are defined in the type space, - // but may be specified either on the type or the variant. - // - // 3. Reference to a fn item or a free constant: - // - // fn foo() { } - // - // In this case, the path will again always have the form - // `a::b::foo::` where only the final segment should have - // type parameters. However, in this case, those parameters are - // declared on a value, and hence are in the `FnSpace`. - // - // 4. Reference to a method or an associated constant: - // - // impl SomeStruct { - // fn foo(...) - // } - // - // Here we can have a path like - // `a::b::SomeStruct::::foo::`, in which case parameters - // may appear in two places. The penultimate segment, - // `SomeStruct::`, contains parameters in TypeSpace, and the - // final segment, `foo::` contains parameters in fn space. - // - // The first step then is to categorize the segments appropriately. +// FIXME(eddyb, varkor) handle type paths here too, not just value ones. +pub fn def_ids_for_value_path_segments<'tcx>( + astconv: &impl AstConv<'tcx>, + segments: &[hir::PathSegment<'_>], + self_ty: Option>, + kind: DefKind, + def_id: DefId, +) -> Vec { + // We need to extract the type parameters supplied by the user in + // the path `path`. Due to the current setup, this is a bit of a + // tricky-process; the problem is that resolve only tells us the + // end-point of the path resolution, and not the intermediate steps. + // Luckily, we can (at least for now) deduce the intermediate steps + // just from the end-point. + // + // There are basically five cases to consider: + // + // 1. Reference to a constructor of a struct: + // + // struct Foo(...) + // + // In this case, the parameters are declared in the type space. + // + // 2. Reference to a constructor of an enum variant: + // + // enum E { Foo(...) } + // + // In this case, the parameters are defined in the type space, + // but may be specified either on the type or the variant. + // + // 3. Reference to a fn item or a free constant: + // + // fn foo() { } + // + // In this case, the path will again always have the form + // `a::b::foo::` where only the final segment should have + // type parameters. However, in this case, those parameters are + // declared on a value, and hence are in the `FnSpace`. + // + // 4. Reference to a method or an associated constant: + // + // impl SomeStruct { + // fn foo(...) + // } + // + // Here we can have a path like + // `a::b::SomeStruct::::foo::`, in which case parameters + // may appear in two places. The penultimate segment, + // `SomeStruct::`, contains parameters in TypeSpace, and the + // final segment, `foo::` contains parameters in fn space. + // + // The first step then is to categorize the segments appropriately. + + let tcx = astconv.tcx(); + + assert!(!segments.is_empty()); + let last = segments.len() - 1; + + let mut path_segs = vec![]; + + match kind { + // Case 1. Reference to a struct constructor. + DefKind::Ctor(CtorOf::Struct, ..) => { + // Everything but the final segment should have no + // parameters at all. + let generics = tcx.generics_of(def_id); + // Variant and struct constructors use the + // generics of their parent type definition. + let generics_def_id = generics.parent.unwrap_or(def_id); + path_segs.push(PathSeg(generics_def_id, last)); + } - let tcx = self.tcx(); + // Case 2. Reference to a variant constructor. + DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { + let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); + let (generics_def_id, index) = if let Some(adt_def) = adt_def { + debug_assert!(adt_def.is_enum()); + (adt_def.did, last) + } else if last >= 1 && segments[last - 1].args.is_some() { + // Everything but the penultimate segment should have no + // parameters at all. + let mut def_id = def_id; - assert!(!segments.is_empty()); - let last = segments.len() - 1; + // `DefKind::Ctor` -> `DefKind::Variant` + if let DefKind::Ctor(..) = kind { + def_id = tcx.parent(def_id).unwrap() + } - let mut path_segs = vec![]; + // `DefKind::Variant` -> `DefKind::Enum` + let enum_def_id = tcx.parent(def_id).unwrap(); + (enum_def_id, last - 1) + } else { + // FIXME: lint here recommending `Enum::<...>::Variant` form + // instead of `Enum::Variant::<...>` form. - match kind { - // Case 1. Reference to a struct constructor. - DefKind::Ctor(CtorOf::Struct, ..) => { // Everything but the final segment should have no // parameters at all. let generics = tcx.generics_of(def_id); // Variant and struct constructors use the // generics of their parent type definition. - let generics_def_id = generics.parent.unwrap_or(def_id); - path_segs.push(PathSeg(generics_def_id, last)); - } - - // Case 2. Reference to a variant constructor. - DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { - let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); - let (generics_def_id, index) = if let Some(adt_def) = adt_def { - debug_assert!(adt_def.is_enum()); - (adt_def.did, last) - } else if last >= 1 && segments[last - 1].args.is_some() { - // Everything but the penultimate segment should have no - // parameters at all. - let mut def_id = def_id; - - // `DefKind::Ctor` -> `DefKind::Variant` - if let DefKind::Ctor(..) = kind { - def_id = tcx.parent(def_id).unwrap() - } - - // `DefKind::Variant` -> `DefKind::Enum` - let enum_def_id = tcx.parent(def_id).unwrap(); - (enum_def_id, last - 1) - } else { - // FIXME: lint here recommending `Enum::<...>::Variant` form - // instead of `Enum::Variant::<...>` form. - - // Everything but the final segment should have no - // parameters at all. - let generics = tcx.generics_of(def_id); - // Variant and struct constructors use the - // generics of their parent type definition. - (generics.parent.unwrap_or(def_id), last) - }; - path_segs.push(PathSeg(generics_def_id, index)); - } + (generics.parent.unwrap_or(def_id), last) + }; + path_segs.push(PathSeg(generics_def_id, index)); + } - // Case 3. Reference to a top-level value. - DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => { - path_segs.push(PathSeg(def_id, last)); - } + // Case 3. Reference to a top-level value. + DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => { + path_segs.push(PathSeg(def_id, last)); + } - // Case 4. Reference to a method or associated const. - DefKind::AssocFn | DefKind::AssocConst => { - if segments.len() >= 2 { - let generics = tcx.generics_of(def_id); - path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); - } - path_segs.push(PathSeg(def_id, last)); + // Case 4. Reference to a method or associated const. + DefKind::AssocFn | DefKind::AssocConst => { + if segments.len() >= 2 { + let generics = tcx.generics_of(def_id); + path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); } - - kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), + path_segs.push(PathSeg(def_id, last)); } - debug!("path_segs = {:?}", path_segs); - - path_segs + kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), } - // Check a type `Path` and convert it to a `Ty`. - pub fn res_to_ty( - &self, - opt_self_ty: Option>, - path: &hir::Path<'_>, - permit_variants: bool, - ) -> Ty<'tcx> { - let tcx = self.tcx(); - - debug!( - "res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})", - path.res, opt_self_ty, path.segments - ); + debug!("path_segs = {:?}", path_segs); - let span = path.span; - match path.res { - Res::Def(DefKind::OpaqueTy, did) => { - // Check for desugared `impl Trait`. - assert!(ty::is_impl_trait_defn(tcx, did).is_none()); - let item_segment = path.segments.split_last().unwrap(); - self.prohibit_generics(item_segment.1); - let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); - self.normalize_ty(span, tcx.mk_opaque(did, substs)) - } - Res::Def( - DefKind::Enum - | DefKind::TyAlias - | DefKind::Struct - | DefKind::Union - | DefKind::ForeignTy, - did, - ) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(span, did, path.segments.last().unwrap()) - } - Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { - // Convert "variant type" as if it were a real type. - // The resulting `Ty` is type of the variant's enum for now. - assert_eq!(opt_self_ty, None); - - let path_segs = - self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); - let generic_segs: FxHashSet<_> = - path_segs.iter().map(|PathSeg(_, index)| index).collect(); - self.prohibit_generics(path.segments.iter().enumerate().filter_map( - |(index, seg)| { - if !generic_segs.contains(&index) { Some(seg) } else { None } - }, - )); + path_segs +} - let PathSeg(def_id, index) = path_segs.last().unwrap(); - self.ast_path_to_ty(span, *def_id, &path.segments[*index]) - } - Res::Def(DefKind::TyParam, def_id) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_ty_param(index, tcx.hir().name(hir_id)) - } - Res::SelfTy(Some(_), None) => { - // `Self` in trait or type alias. - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - tcx.types.self_param - } - Res::SelfTy(_, Some((def_id, forbid_generic))) => { - // `Self` in impl (we know the concrete type). - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - // Try to evaluate any array length constants. - let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); - if forbid_generic && normalized_ty.needs_subst() { - let mut err = tcx.sess.struct_span_err( - path.span, - "generic `Self` types are currently not permitted in anonymous constants", - ); - if let Some(hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Impl { self_ty, .. }, - .. - })) = tcx.hir().get_if_local(def_id) - { - err.span_note(self_ty.span, "not a concrete type"); - } - err.emit(); - tcx.ty_error() - } else { - normalized_ty - } - } - Res::Def(DefKind::AssocTy, def_id) => { - debug_assert!(path.segments.len() >= 2); - self.prohibit_generics(&path.segments[..path.segments.len() - 2]); - self.qpath_to_ty( - span, - opt_self_ty, - def_id, - &path.segments[path.segments.len() - 2], - path.segments.last().unwrap(), - ) - } - Res::PrimTy(prim_ty) => { - assert_eq!(opt_self_ty, None); - self.prohibit_generics(path.segments); - match prim_ty { - hir::PrimTy::Bool => tcx.types.bool, - hir::PrimTy::Char => tcx.types.char, - hir::PrimTy::Int(it) => tcx.mk_mach_int(it), - hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit), - hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft), - hir::PrimTy::Str => tcx.types.str_, +// Check a type `Path` and convert it to a `Ty`. +pub fn res_to_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + opt_self_ty: Option>, + path: &hir::Path<'_>, + permit_variants: bool, +) -> Ty<'tcx> { + let tcx = astconv.tcx(); + + debug!( + "res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})", + path.res, opt_self_ty, path.segments + ); + + let span = path.span; + match path.res { + Res::Def(DefKind::OpaqueTy, did) => { + // Check for desugared `impl Trait`. + assert!(ty::is_impl_trait_defn(tcx, did).is_none()); + let item_segment = path.segments.split_last().unwrap(); + prohibit_generics(astconv, item_segment.1); + let substs = ast_path_substs_for_ty(astconv, span, did, item_segment.0); + astconv.normalize_ty(span, tcx.mk_opaque(did, substs)) + } + Res::Def( + DefKind::Enum + | DefKind::TyAlias + | DefKind::Struct + | DefKind::Union + | DefKind::ForeignTy, + did, + ) => { + assert_eq!(opt_self_ty, None); + prohibit_generics(astconv, path.segments.split_last().unwrap().1); + ast_path_to_ty(astconv, span, did, path.segments.last().unwrap()) + } + Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { + // Convert "variant type" as if it were a real type. + // The resulting `Ty` is type of the variant's enum for now. + assert_eq!(opt_self_ty, None); + + let path_segs = + def_ids_for_value_path_segments(astconv, &path.segments, None, kind, def_id); + let generic_segs: FxHashSet<_> = + path_segs.iter().map(|PathSeg(_, index)| index).collect(); + prohibit_generics( + astconv, + path.segments.iter().enumerate().filter_map(|(index, seg)| { + if !generic_segs.contains(&index) { Some(seg) } else { None } + }), + ); + + let PathSeg(def_id, index) = path_segs.last().unwrap(); + ast_path_to_ty(astconv, span, *def_id, &path.segments[*index]) + } + Res::Def(DefKind::TyParam, def_id) => { + assert_eq!(opt_self_ty, None); + prohibit_generics(astconv, path.segments); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_ty_param(index, tcx.hir().name(hir_id)) + } + Res::SelfTy(Some(_), None) => { + // `Self` in trait or type alias. + assert_eq!(opt_self_ty, None); + prohibit_generics(astconv, path.segments); + tcx.types.self_param + } + Res::SelfTy(_, Some((def_id, forbid_generic))) => { + // `Self` in impl (we know the concrete type). + assert_eq!(opt_self_ty, None); + prohibit_generics(astconv, path.segments); + // Try to evaluate any array length constants. + let normalized_ty = astconv.normalize_ty(span, tcx.at(span).type_of(def_id)); + if forbid_generic && normalized_ty.needs_subst() { + let mut err = tcx.sess.struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants", + ); + if let Some(hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Impl { self_ty, .. }, + .. + })) = tcx.hir().get_if_local(def_id) + { + err.span_note(self_ty.span, "not a concrete type"); } + err.emit(); + tcx.ty_error() + } else { + normalized_ty } - Res::Err => { - self.set_tainted_by_errors(); - self.tcx().ty_error() + } + Res::Def(DefKind::AssocTy, def_id) => { + debug_assert!(path.segments.len() >= 2); + prohibit_generics(astconv, &path.segments[..path.segments.len() - 2]); + qpath_to_ty( + astconv, + span, + opt_self_ty, + def_id, + &path.segments[path.segments.len() - 2], + path.segments.last().unwrap(), + ) + } + Res::PrimTy(prim_ty) => { + assert_eq!(opt_self_ty, None); + prohibit_generics(astconv, path.segments); + match prim_ty { + hir::PrimTy::Bool => tcx.types.bool, + hir::PrimTy::Char => tcx.types.char, + hir::PrimTy::Int(it) => tcx.mk_mach_int(it), + hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit), + hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft), + hir::PrimTy::Str => tcx.types.str_, } - _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } + Res::Err => { + astconv.set_tainted_by_errors(); + tcx.ty_error() + } + _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } +} - /// Parses the programmer's textual representation of a type into our - /// internal notion of a type. - pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { - self.ast_ty_to_ty_inner(ast_ty, false) - } - - /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait - /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. - fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> { - debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind); - - let tcx = self.tcx(); +/// Parses the programmer's textual representation of a type into our +/// internal notion of a type. +pub fn ast_ty_to_ty<'tcx>(astconv: &impl AstConv<'tcx>, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + ast_ty_to_ty_inner(astconv, ast_ty, false) +} - let result_ty = match ast_ty.kind { - hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)), - hir::TyKind::Ptr(ref mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) - } - hir::TyKind::Rptr(ref region, ref mt) => { - let r = self.ast_region_to_region(region, None); - debug!("ast_ty_to_ty: r={:?}", r); - let t = self.ast_ty_to_ty_inner(&mt.ty, true); - tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) - } - hir::TyKind::Never => tcx.types.never, - hir::TyKind::Tup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) - } - hir::TyKind::BareFn(ref bf) => { - require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_fn( - bf.unsafety, - bf.abi, - &bf.decl, - &hir::Generics::empty(), - None, - )) - } - hir::TyKind::TraitObject(ref bounds, ref lifetime) => { - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) - } - hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { - debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); - let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); - self.res_to_ty(opt_self_ty, path, false) - } - hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { - let opaque_ty = tcx.hir().expect_item(item_id.id); - let def_id = tcx.hir().local_def_id(item_id.id).to_def_id(); +/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait +/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. +fn ast_ty_to_ty_inner<'tcx>( + astconv: &impl AstConv<'tcx>, + ast_ty: &hir::Ty<'_>, + borrowed: bool, +) -> Ty<'tcx> { + debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind); + + let tcx = astconv.tcx(); + + let result_ty = match ast_ty.kind { + hir::TyKind::Slice(ref ty) => tcx.mk_slice(ast_ty_to_ty(astconv, &ty)), + hir::TyKind::Ptr(ref mt) => { + tcx.mk_ptr(ty::TypeAndMut { ty: ast_ty_to_ty(astconv, &mt.ty), mutbl: mt.mutbl }) + } + hir::TyKind::Rptr(ref region, ref mt) => { + let r = ast_region_to_region(astconv, region, None); + debug!("ast_ty_to_ty: r={:?}", r); + let t = ast_ty_to_ty_inner(astconv, &mt.ty, true); + tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) + } + hir::TyKind::Never => tcx.types.never, + hir::TyKind::Tup(ref fields) => { + tcx.mk_tup(fields.iter().map(|t| ast_ty_to_ty(astconv, &t))) + } + hir::TyKind::BareFn(ref bf) => { + require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + tcx.mk_fn_ptr(ty_of_fn( + astconv, + bf.unsafety, + bf.abi, + &bf.decl, + &hir::Generics::empty(), + None, + )) + } + hir::TyKind::TraitObject(ref bounds, ref lifetime) => { + conv_object_ty_poly_trait_ref(astconv, ast_ty.span, bounds, lifetime, borrowed) + } + hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { + debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| ast_ty_to_ty(astconv, qself)); + res_to_ty(astconv, opt_self_ty, path, false) + } + hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { + let opaque_ty = tcx.hir().expect_item(item_id.id); + let def_id = tcx.hir().local_def_id(item_id.id).to_def_id(); - match opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { - self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some()) - } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + match opaque_ty.kind { + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { + impl_trait_ty_to_ty(astconv, def_id, lifetimes, impl_trait_fn.is_some()) } + ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } - hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { - debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); - let ty = self.ast_ty_to_ty(qself); + } + hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { + debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); + let ty = ast_ty_to_ty(astconv, qself); - let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { - path.res - } else { - Res::Err - }; - self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) - .map(|(ty, _, _)| ty) - .unwrap_or_else(|_| tcx.ty_error()) - } - hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { - let def_id = tcx.require_lang_item(lang_item, Some(span)); - let (substs, _, _) = self.create_substs_for_ast_path( - span, - def_id, - &[], - &GenericArgs::none(), - true, - None, - ); - self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) - } - hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_anon_const(tcx, length_def_id); - let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); - self.normalize_ty(ast_ty.span, array_ty) - } - hir::TyKind::Typeof(ref _e) => { - tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); - tcx.ty_error() - } - hir::TyKind::Infer => { - // Infer also appears as the type of arguments or return - // values in a ExprKind::Closure, or as - // the type of local variables. Both of these cases are - // handled specially and will not descend into this routine. - self.ty_infer(None, ast_ty.span) - } - hir::TyKind::Err => tcx.ty_error(), - }; + let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { + path.res + } else { + Res::Err + }; + associated_path_to_ty(astconv, ast_ty.hir_id, ast_ty.span, ty, res, segment, false) + .map(|(ty, _, _)| ty) + .unwrap_or_else(|_| tcx.ty_error()) + } + hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { + let def_id = tcx.require_lang_item(lang_item, Some(span)); + let (substs, _, _) = create_substs_for_ast_path( + astconv, + span, + def_id, + &[], + &GenericArgs::none(), + true, + None, + ); + astconv.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) + } + hir::TyKind::Array(ref ty, ref length) => { + let length_def_id = tcx.hir().local_def_id(length.hir_id); + let length = ty::Const::from_anon_const(tcx, length_def_id); + let array_ty = tcx.mk_ty(ty::Array(ast_ty_to_ty(astconv, &ty), length)); + astconv.normalize_ty(ast_ty.span, array_ty) + } + hir::TyKind::Typeof(ref _e) => { + tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); + tcx.ty_error() + } + hir::TyKind::Infer => { + // Infer also appears as the type of arguments or return + // values in a ExprKind::Closure, or as + // the type of local variables. Both of these cases are + // handled specially and will not descend into this routine. + astconv.ty_infer(None, ast_ty.span) + } + hir::TyKind::Err => tcx.ty_error(), + }; - debug!("ast_ty_to_ty: result_ty={:?}", result_ty); + debug!("ast_ty_to_ty: result_ty={:?}", result_ty); - self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); - result_ty - } + astconv.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); + result_ty +} - pub fn impl_trait_ty_to_ty( - &self, - def_id: DefId, - lifetimes: &[hir::GenericArg<'_>], - replace_parent_lifetimes: bool, - ) -> Ty<'tcx> { - debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); - let tcx = self.tcx(); - - let generics = tcx.generics_of(def_id); - - debug!("impl_trait_ty_to_ty: generics={:?}", generics); - let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { - if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { - // Our own parameters are the resolved lifetimes. - match param.kind { - GenericParamDefKind::Lifetime => { - if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { - self.ast_region_to_region(lifetime, None).into() - } else { - bug!() - } +pub fn impl_trait_ty_to_ty<'tcx>( + astconv: &impl AstConv<'tcx>, + def_id: DefId, + lifetimes: &[hir::GenericArg<'_>], + replace_parent_lifetimes: bool, +) -> Ty<'tcx> { + debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); + let tcx = astconv.tcx(); + + let generics = tcx.generics_of(def_id); + + debug!("impl_trait_ty_to_ty: generics={:?}", generics); + let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { + if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { + // Our own parameters are the resolved lifetimes. + match param.kind { + GenericParamDefKind::Lifetime => { + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { + ast_region_to_region(astconv, lifetime, None).into() + } else { + bug!() } - _ => bug!(), } - } else { - match param.kind { - // For RPIT (return position impl trait), only lifetimes - // mentioned in the impl Trait predicate are captured by - // the opaque type, so the lifetime parameters from the - // parent item need to be replaced with `'static`. - // - // For `impl Trait` in the types of statics, constants, - // locals and type aliases. These capture all parent - // lifetimes, so they can use their identity subst. - GenericParamDefKind::Lifetime if replace_parent_lifetimes => { - tcx.lifetimes.re_static.into() - } - _ => tcx.mk_param_from_def(param), + _ => bug!(), + } + } else { + match param.kind { + // For RPIT (return position impl trait), only lifetimes + // mentioned in the impl Trait predicate are captured by + // the opaque type, so the lifetime parameters from the + // parent item need to be replaced with `'static`. + // + // For `impl Trait` in the types of statics, constants, + // locals and type aliases. These capture all parent + // lifetimes, so they can use their identity subst. + GenericParamDefKind::Lifetime if replace_parent_lifetimes => { + tcx.lifetimes.re_static.into() } + _ => tcx.mk_param_from_def(param), } - }); - debug!("impl_trait_ty_to_ty: substs={:?}", substs); + } + }); + debug!("impl_trait_ty_to_ty: substs={:?}", substs); - let ty = tcx.mk_opaque(def_id, substs); - debug!("impl_trait_ty_to_ty: {}", ty); - ty - } + let ty = tcx.mk_opaque(def_id, substs); + debug!("impl_trait_ty_to_ty: {}", ty); + ty +} - pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { - match ty.kind { - hir::TyKind::Infer if expected_ty.is_some() => { - self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span); - expected_ty.unwrap() - } - _ => self.ast_ty_to_ty(ty), +pub fn ty_of_arg<'tcx>( + astconv: &impl AstConv<'tcx>, + ty: &hir::Ty<'_>, + expected_ty: Option>, +) -> Ty<'tcx> { + match ty.kind { + hir::TyKind::Infer if expected_ty.is_some() => { + astconv.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span); + expected_ty.unwrap() } + _ => ast_ty_to_ty(astconv, ty), } +} - pub fn ty_of_fn( - &self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl<'_>, - generics: &hir::Generics<'_>, - ident_span: Option, - ) -> ty::PolyFnSig<'tcx> { - debug!("ty_of_fn"); - - let tcx = self.tcx(); - - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = PlaceholderHirTyCollector::default(); - for ty in decl.inputs { - visitor.visit_ty(ty); - } - walk_generics(&mut visitor, generics); +pub fn ty_of_fn<'tcx>( + astconv: &impl AstConv<'tcx>, + unsafety: hir::Unsafety, + abi: abi::Abi, + decl: &hir::FnDecl<'_>, + generics: &hir::Generics<'_>, + ident_span: Option, +) -> ty::PolyFnSig<'tcx> { + debug!("ty_of_fn"); + + let tcx = astconv.tcx(); + + // We proactively collect all the inferred type params to emit a single error per fn def. + let mut visitor = PlaceholderHirTyCollector::default(); + for ty in decl.inputs { + visitor.visit_ty(ty); + } + walk_generics(&mut visitor, generics); - let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); - let output_ty = match decl.output { - hir::FnRetTy::Return(ref output) => { - visitor.visit_ty(output); - self.ast_ty_to_ty(output) - } - hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), - }; + let input_tys = decl.inputs.iter().map(|a| ty_of_arg(astconv, a, None)); + let output_ty = match decl.output { + hir::FnRetTy::Return(ref output) => { + visitor.visit_ty(output); + ast_ty_to_ty(astconv, output) + } + hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), + }; - debug!("ty_of_fn: output_ty={:?}", output_ty); + debug!("ty_of_fn: output_ty={:?}", output_ty); - let bare_fn_ty = - ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); + let bare_fn_ty = + ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); - if !self.allow_ty_infer() { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_ty_infer` gates this behavior. We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - crate::collect::placeholder_type_error( - tcx, - ident_span.map(|sp| sp.shrink_to_hi()), - &generics.params[..], - visitor.0, - true, - ); - } + if !astconv.allow_ty_infer() { + // We always collect the spans for placeholder types when evaluating `fn`s, but we + // only want to emit an error complaining about them if infer types (`_`) are not + // allowed. `allow_ty_infer` gates this behavior. We check for the presence of + // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. + crate::collect::placeholder_type_error( + tcx, + ident_span.map(|sp| sp.shrink_to_hi()), + &generics.params[..], + visitor.0, + true, + ); + } - // Find any late-bound regions declared in return type that do - // not appear in the arguments. These are not well-formed. - // - // Example: - // for<'a> fn() -> &'a str <-- 'a is bad - // for<'a> fn(&'a String) -> &'a str <-- 'a is ok - let inputs = bare_fn_ty.inputs(); - let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); - let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); - - self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { - struct_span_err!( - tcx.sess, - decl.output.span(), - E0581, - "return type references {}, which is not constrained by the fn input types", - br_name - ) - }); + // Find any late-bound regions declared in return type that do + // not appear in the arguments. These are not well-formed. + // + // Example: + // for<'a> fn() -> &'a str <-- 'a is bad + // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + let inputs = bare_fn_ty.inputs(); + let late_bound_in_args = + tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); + let output = bare_fn_ty.output(); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + + validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { + struct_span_err!( + tcx.sess, + decl.output.span(), + E0581, + "return type references {}, which is not constrained by the fn input types", + br_name + ) + }); - bare_fn_ty - } + bare_fn_ty +} - fn validate_late_bound_regions( - &self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, - generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, - ) { - for br in referenced_regions.difference(&constrained_regions) { - let br_name = match *br { - ty::BrNamed(_, name) => format!("lifetime `{}`", name), - ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), - }; +fn validate_late_bound_regions<'tcx>( + constrained_regions: FxHashSet, + referenced_regions: FxHashSet, + generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, +) { + for br in referenced_regions.difference(&constrained_regions) { + let br_name = match *br { + ty::BrNamed(_, name) => format!("lifetime `{}`", name), + ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), + }; - let mut err = generate_err(&br_name); - - if let ty::BrAnon(_) = *br { - // The only way for an anonymous lifetime to wind up - // in the return type but **also** be unconstrained is - // if it only appears in "associated types" in the - // input. See #47511 and #62200 for examples. In this case, - // though we can easily give a hint that ought to be - // relevant. - err.note( - "lifetimes appearing in an associated type are not considered constrained", - ); - } + let mut err = generate_err(&br_name); - err.emit(); + if let ty::BrAnon(_) = *br { + // The only way for an anonymous lifetime to wind up + // in the return type but **also** be unconstrained is + // if it only appears in "associated types" in the + // input. See #47511 and #62200 for examples. In this case, + // though we can easily give a hint that ought to be + // relevant. + err.note("lifetimes appearing in an associated type are not considered constrained"); } + + err.emit(); } +} - /// Given the bounds on an object, determines what single region bound (if any) we can - /// use to summarize this type. The basic idea is that we will use the bound the user - /// provided, if they provided one, and otherwise search the supertypes of trait bounds - /// for region bounds. It may be that we can derive no bound at all, in which case - /// we return `None`. - fn compute_object_lifetime_bound( - &self, - span: Span, - existential_predicates: &'tcx ty::List>>, - ) -> Option> // if None, use the default - { - let tcx = self.tcx(); +/// Given the bounds on an object, determines what single region bound (if any) we can +/// use to summarize this type. The basic idea is that we will use the bound the user +/// provided, if they provided one, and otherwise search the supertypes of trait bounds +/// for region bounds. It may be that we can derive no bound at all, in which case +/// we return `None`. +fn compute_object_lifetime_bound<'tcx>( + astconv: &impl AstConv<'tcx>, + span: Span, + existential_predicates: &'tcx ty::List>>, +) -> Option> // if None, use the default +{ + let tcx = astconv.tcx(); - debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); + debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); - // No explicit region bound specified. Therefore, examine trait - // bounds and see if we can derive region bounds from those. - let derived_region_bounds = object_region_bounds(tcx, existential_predicates); + // No explicit region bound specified. Therefore, examine trait + // bounds and see if we can derive region bounds from those. + let derived_region_bounds = object_region_bounds(tcx, existential_predicates); - // If there are no derived region bounds, then report back that we - // can find no region bound. The caller will use the default. - if derived_region_bounds.is_empty() { - return None; - } + // If there are no derived region bounds, then report back that we + // can find no region bound. The caller will use the default. + if derived_region_bounds.is_empty() { + return None; + } - // If any of the derived region bounds are 'static, that is always - // the best choice. - if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.lifetimes.re_static); - } + // If any of the derived region bounds are 'static, that is always + // the best choice. + if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { + return Some(tcx.lifetimes.re_static); + } - // Determine whether there is exactly one unique region in the set - // of derived region bounds. If so, use that. Otherwise, report an - // error. - let r = derived_region_bounds[0]; - if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - tcx.sess.emit_err(AmbiguousLifetimeBound { span }); - } - Some(r) + // Determine whether there is exactly one unique region in the set + // of derived region bounds. If so, use that. Otherwise, report an + // error. + let r = derived_region_bounds[0]; + if derived_region_bounds[1..].iter().any(|r1| r != *r1) { + tcx.sess.emit_err(AmbiguousLifetimeBound { span }); } + Some(r) } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 7470c1a76a943..745426bffd148 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -2,7 +2,7 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; -use crate::astconv::AstConv; +use crate::astconv::{self, AstConv}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -538,17 +538,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, ) -> ty::PolyFnSig<'tcx> { - let astconv: &dyn AstConv<'_> = self; - debug!( "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})", decl, body.generator_kind, ); // First, convert the types that the user supplied (if any). - let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); + let supplied_arguments = decl.inputs.iter().map(|a| astconv::ast_ty_to_ty(self, a)); let supplied_return = match decl.output { - hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(&output), + hir::FnRetTy::Return(ref output) => astconv::ast_ty_to_ty(self, &output), hir::FnRetTy::DefaultReturn(_) => match body.generator_kind { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing @@ -563,11 +561,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // easily (and locally) prove that we // *have* reported an // error. --nikomatsakis - astconv.ty_infer(None, decl.output.span()) + self.ty_infer(None, decl.output.span()) }) } - _ => astconv.ty_infer(None, decl.output.span()), + _ => self.ty_infer(None, decl.output.span()), }, }; @@ -694,16 +692,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// so should yield an error, but returns back a signature where /// all parameters are of type `TyErr`. fn error_sig_of_closure(&self, decl: &hir::FnDecl<'_>) -> ty::PolyFnSig<'tcx> { - let astconv: &dyn AstConv<'_> = self; - let supplied_arguments = decl.inputs.iter().map(|a| { // Convert the types that the user supplied (if any), but ignore them. - astconv.ast_ty_to_ty(a); + astconv::ast_ty_to_ty(self, a); self.tcx.ty_error() }); if let hir::FnRetTy::Return(ref output) = decl.output { - astconv.ast_ty_to_ty(&output); + astconv::ast_ty_to_ty(self, &output); } let result = ty::Binder::dummy(self.tcx.mk_fn_sig( diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 0f5f0ab026087..187ee6134b9f4 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -35,7 +35,7 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` -use crate::astconv::AstConv; +use crate::astconv; use crate::check::FnCtxt; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -1536,7 +1536,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let hir::FnRetTy::Return(ty) = fn_output { // Get the return type. if let hir::TyKind::OpaqueDef(..) = ty.kind { - let ty = AstConv::ast_ty_to_ty(fcx, ty); + let ty = astconv::ast_ty_to_ty(fcx, ty); // Get the `impl Trait`'s `DefId`. if let ty::Opaque(def_id, _) = ty.kind() { let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); @@ -1598,7 +1598,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) { if let hir::FnRetTy::Return(ty) = fn_decl.output { - let ty = AstConv::ast_ty_to_ty(fcx, ty); + let ty = astconv::ast_ty_to_ty(fcx, ty); if let ty::Dynamic(..) = ty.kind() { return true; } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7126b62405968..18d23309bc126 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1,5 +1,5 @@ use crate::astconv::{ - AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + self, AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, }; use crate::check::callee::{self, DeferredCallResolution}; @@ -454,7 +454,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, ast_t); + let t = astconv::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); t } @@ -1144,7 +1144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let path_segs = match res { Res::Local(_) | Res::SelfCtor(_) => vec![], Res::Def(kind, def_id) => { - AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) + astconv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) } _ => bug!("instantiate_value_path on {:?}", res), }; @@ -1188,7 +1188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // errors if type parameters are provided in an inappropriate place. let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); - let generics_has_err = AstConv::prohibit_generics( + let generics_has_err = astconv::prohibit_generics( self, segments.iter().enumerate().filter_map(|(index, seg)| { if !generic_segs.contains(&index) || is_alias_variant_ctor { @@ -1229,7 +1229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let GenericArgCountResult { correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), .. - } = AstConv::check_generic_arg_count_for_call( + } = astconv::generics::check_generic_arg_count_for_call( tcx, span, &generics, &seg, false, // `is_method_call` ) { infer_args_for_err.insert(index); @@ -1332,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> subst::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() + astconv::ast_region_to_region(self.fcx, lt, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.fcx.to_ty(ty).into() @@ -1385,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( + astconv::generics::create_substs_for_generic_args( tcx, def_id, &[][..], diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3e60924d6fcf8..66bccd6457b36 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1,4 +1,4 @@ -use crate::astconv::AstConv; +use crate::astconv::{self, AstConv}; use crate::check::coercion::CoerceMany; use crate::check::method::MethodCallee; use crate::check::Expectation::*; @@ -860,7 +860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *qpath { QPath::Resolved(ref maybe_qself, ref path) => { let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::res_to_ty(self, self_ty, path, true); + let ty = astconv::res_to_ty(self, self_ty, path, true); (path.res, ty) } QPath::TypeRelative(ref qself, ref segment) => { @@ -872,7 +872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Err }; let result = - AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); + astconv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); let result = result.map(|(_, kind, def_id)| (kind, def_id)); @@ -985,7 +985,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // would trigger in `is_send::();` // from `typeck-default-trait-impl-assoc-type.rs`. } else { - let ty = AstConv::ast_ty_to_ty(self, hir_ty); + let ty = astconv::ast_ty_to_ty(self, hir_ty); let ty = self.resolve_vars_if_possible(ty); if ty == predicate.self_ty() { error.obligation.cause.make_mut().span = hir_ty.span; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index f635e0b6f931c..f93aca849d229 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -6,7 +6,7 @@ pub use _impl::*; pub use checks::*; pub use suggestions::*; -use crate::astconv::AstConv; +use crate::astconv::{self, AstConv}; use crate::check::coercion::DynamicCoerceMany; use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; @@ -265,7 +265,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { poly_trait_ref, ); - let item_substs = >::create_substs_for_associated_item( + let item_substs = astconv::create_substs_for_associated_item( self, self.tcx, span, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 17dbf989d6683..f5325f307aaa1 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -1,5 +1,5 @@ use super::FnCtxt; -use crate::astconv::AstConv; +use crate::astconv; use rustc_ast::util::parser::ExprPrecedence; use rustc_span::{self, Span}; @@ -419,7 +419,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // are not, the expectation must have been caused by something else. debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); let sp = ty.span; - let ty = AstConv::ast_ty_to_ty(self, ty); + let ty = astconv::ast_ty_to_ty(self, ty); debug!("suggest_missing_return_type: return type {:?}", ty); debug!("suggest_missing_return_type: expected type {:?}", ty); if ty.kind() == expected.kind() { diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 8ef723d590285..021b343290794 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -1,6 +1,6 @@ use super::{probe, MethodCallee}; -use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt}; +use crate::astconv::{self, CreateSubstsForGenericArgsCtxt}; use crate::check::{callee, FnCtxt}; use crate::hir::def_id::DefId; use crate::hir::GenericArg; @@ -298,7 +298,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let generics = self.tcx.generics_of(pick.item.def_id); - let arg_count_correct = AstConv::check_generic_arg_count_for_call( + let arg_count_correct = astconv::generics::check_generic_arg_count_for_call( self.tcx, self.span, &generics, &seg, true, // `is_method_call` ); @@ -331,7 +331,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> subst::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into() + astconv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.cfcx.to_ty(ty).into() @@ -352,7 +352,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.var_for_def(self.cfcx.span, param) } } - AstConv::create_substs_for_generic_args( + astconv::generics::create_substs_for_generic_args( self.tcx, pick.item.def_id, parent_substs, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 8177b363a5a5b..1588a02b8f793 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,7 +99,7 @@ pub use expectation::Expectation; pub use fn_ctxt::*; pub use inherited::{Inherited, InheritedBuilder}; -use crate::astconv::AstConv; +use crate::astconv::{self, AstConv}; use crate::check::gather_locals::GatherLocalsVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; @@ -495,7 +495,7 @@ fn typeck_with_fallback<'tcx>( let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - AstConv::ty_of_fn( + astconv::ty_of_fn( &fcx, header.unsafety, header.abi, @@ -526,7 +526,7 @@ fn typeck_with_fallback<'tcx>( let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); let expected_type = body_ty .and_then(|ty| match ty.kind { - hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), + hir::TyKind::Infer => Some(astconv::ast_ty_to_ty(&fcx, ty)), _ => None, }) .unwrap_or_else(|| match tcx.hir().get(id) { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2ebb1a3be4e44..6ebc645fc05ae 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -14,7 +14,7 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::{self, AstConv, SizedByDefault}; use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; @@ -281,7 +281,7 @@ impl ItemCtxt<'tcx> { } pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> { - AstConv::ast_ty_to_ty(self, ast_ty) + astconv::ast_ty_to_ty(self, ast_ty) } pub fn hir_id(&self) -> hir::HirId { @@ -344,7 +344,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { - let item_substs = >::create_substs_for_associated_item( + let item_substs = astconv::create_substs_for_associated_item( self, self.tcx, span, @@ -1003,7 +1003,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. let self_param_ty = tcx.types.self_param; let superbounds1 = - AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); + astconv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1569,7 +1569,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { diag.emit(); ty::Binder::bind(fn_sig) } - None => AstConv::ty_of_fn( + None => astconv::ty_of_fn( &icx, sig.header.unsafety, sig.header.abi, @@ -1586,7 +1586,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { generics, .. }) => { - AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span)) + astconv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span)) } ForeignItem(&hir::ForeignItem { @@ -1640,7 +1640,7 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { match tcx.hir().expect_item(hir_id).kind { hir::ItemKind::Impl { ref of_trait, .. } => of_trait.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id); - AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty) + astconv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty) }), _ => bug!(), } @@ -1881,7 +1881,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP GenericParamKind::Lifetime { .. } => { param.bounds.iter().for_each(|bound| match bound { hir::GenericBound::Outlives(lt) => { - let bound = AstConv::ast_region_to_region(&icx, <, None); + let bound = astconv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); predicates.insert((outlives.to_predicate(tcx), lt.span)); } @@ -1905,7 +1905,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let sized = SizedByDefault::Yes; let bounds = - AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); + astconv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); predicates.extend(bounds.predicates(tcx, param_ty)); } GenericParamKind::Const { .. } => { @@ -1957,7 +1957,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP }; let mut bounds = Bounds::default(); - let _ = AstConv::instantiate_poly_trait_ref( + let _ = astconv::instantiate_poly_trait_ref( &icx, poly_trait_ref, constness, @@ -1969,7 +1969,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { let mut bounds = Bounds::default(); - AstConv::instantiate_lang_item_trait_ref( + astconv::instantiate_lang_item_trait_ref( &icx, lang_item, span, @@ -1982,7 +1982,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } &hir::GenericBound::Outlives(ref lifetime) => { - let region = AstConv::ast_region_to_region(&icx, lifetime, None); + let region = astconv::ast_region_to_region(&icx, lifetime, None); predicates.insert(( ty::Binder::bind(ty::PredicateAtom::TypeOutlives( ty::OutlivesPredicate(ty, region), @@ -1996,11 +1996,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } &hir::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = AstConv::ast_region_to_region(&icx, ®ion_pred.lifetime, None); + let r1 = astconv::ast_region_to_region(&icx, ®ion_pred.lifetime, None); predicates.extend(region_pred.bounds.iter().map(|bound| { let (r2, span) = match bound { hir::GenericBound::Outlives(lt) => { - (AstConv::ast_region_to_region(&icx, lt, None), lt.span) + (astconv::ast_region_to_region(&icx, lt, None), lt.span) } _ => bug!(), }; @@ -2224,11 +2224,12 @@ fn projection_ty_from_predicates( /// predicates) to one (`T: Foo`) to many (`T: Bar` adds `T: Bar` /// and `::X == i32`). fn predicates_from_bound<'tcx>( - astconv: &dyn AstConv<'tcx>, + astconv_inst: &impl AstConv<'tcx>, param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, constness: hir::Constness, ) -> Vec<(ty::Predicate<'tcx>, Span)> { + let tcx = astconv_inst.tcx(); match *bound { hir::GenericBound::Trait(ref tr, modifier) => { let constness = match modifier { @@ -2238,12 +2239,19 @@ fn predicates_from_bound<'tcx>( }; let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); - bounds.predicates(astconv.tcx(), param_ty) + let _ = astconv::instantiate_poly_trait_ref( + astconv_inst, + tr, + constness, + param_ty, + &mut bounds, + ); + bounds.predicates(tcx, param_ty) } hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { let mut bounds = Bounds::default(); - astconv.instantiate_lang_item_trait_ref( + astconv::instantiate_lang_item_trait_ref( + astconv_inst, lang_item, span, hir_id, @@ -2251,12 +2259,12 @@ fn predicates_from_bound<'tcx>( param_ty, &mut bounds, ); - bounds.predicates(astconv.tcx(), param_ty) + bounds.predicates(tcx, param_ty) } hir::GenericBound::Outlives(ref lifetime) => { - let region = astconv.ast_region_to_region(lifetime, None); + let region = astconv::ast_region_to_region(astconv_inst, lifetime, None); let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) - .to_predicate(astconv.tcx()); + .to_predicate(tcx); vec![(pred, lifetime.span)] } } @@ -2274,7 +2282,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } else { hir::Unsafety::Unsafe }; - let fty = AstConv::ty_of_fn( + let fty = astconv::ty_of_fn( &ItemCtxt::new(tcx, def_id), unsafety, abi, diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index e596dd1a396c9..27dad7676beef 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -1,5 +1,5 @@ use super::ItemCtxt; -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::{self, SizedByDefault}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; @@ -25,7 +25,7 @@ fn associated_type_bounds<'tcx>( InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); - let bounds = AstConv::compute_bounds( + let bounds = astconv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, bounds, @@ -65,7 +65,7 @@ fn opaque_type_bounds<'tcx>( let item_ty = tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); - let bounds = AstConv::compute_bounds( + let bounds = astconv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, bounds, diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index dde4a62ffbf3d..d9f7053af9b8c 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -113,7 +113,6 @@ use rustc_trait_selection::traits::{ use std::iter; -use astconv::AstConv; use bounds::Bounds; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { @@ -422,7 +421,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let env_def_id = tcx.hir().local_def_id(env_node_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); - astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty) + astconv::ast_ty_to_ty(&item_cx, hir_ty) } pub fn hir_trait_to_predicates<'tcx>( @@ -437,7 +436,7 @@ pub fn hir_trait_to_predicates<'tcx>( let env_def_id = tcx.hir().local_def_id(env_hir_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); let mut bounds = Bounds::default(); - let _ = AstConv::instantiate_poly_trait_ref_inner( + let _ = astconv::instantiate_poly_trait_ref_inner( &item_cx, hir_trait, DUMMY_SP, From d6695bd4ef82b4a9b7fc9b01b56f7204758e704e Mon Sep 17 00:00:00 2001 From: kadmin Date: Fri, 25 Dec 2020 02:16:44 +0000 Subject: [PATCH 4/4] One more minor allocation optimization Remove one unnecessary collect at the end of a fn --- compiler/rustc_typeck/src/astconv/generics.rs | 22 +++++++++++++++++++ compiler/rustc_typeck/src/collect.rs | 16 +++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b00a5b697492a..97295ce0b1ec3 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -333,6 +333,28 @@ pub fn create_substs_for_generic_args<'a, 'tcx>( tcx.intern_substs(&substs) } +/// Checks that the correct number of generic arguments have been provided. +/// Used specifically for function calls. +pub fn check_generic_arg_count_for_call( + tcx: TyCtxt<'_>, + span: Span, + def: &ty::Generics, + seg: &hir::PathSegment<'_>, + is_method_call: bool, +) -> GenericArgCountResult { + let empty_args = hir::GenericArgs::none(); + let suppress_mismatch = check_impl_trait(tcx, seg, &def); + check_generic_arg_count( + tcx, + span, + def, + if let Some(ref args) = seg.args { args } else { &empty_args }, + if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value }, + def.parent.is_none() && def.has_self, // `has_self` + seg.infer_args || suppress_mismatch, // `infer_args` + ) +} + /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. pub(crate) fn check_generic_arg_count( diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6ebc645fc05ae..60e5b622ae3a1 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -583,27 +583,27 @@ impl ItemCtxt<'tcx> { param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, - ) -> Vec<(ty::Predicate<'tcx>, Span)> { + ) -> impl Iterator, Span)> + '_ { let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics .params .iter() - .filter_map(|param| match param.kind { + .filter_map(move |param| match param.kind { GenericParamKind::Type { .. } if param.hir_id == param_id => Some(¶m.bounds), _ => None, }) - .flat_map(|bounds| bounds.iter()) - .flat_map(|b| predicates_from_bound(self, ty, b, constness)); + .flat_map(move |bounds| bounds.iter()) + .flat_map(move |b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics .where_clause .predicates .iter() - .filter_map(|wp| match *wp { + .filter_map(move |wp| match *wp { hir::WherePredicate::BoundPredicate(ref bp) => Some(bp), _ => None, }) - .flat_map(|bp| { + .flat_map(move |bp| { let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { Some(ty) } else if !only_self_bounds.0 { @@ -613,9 +613,9 @@ impl ItemCtxt<'tcx> { }; bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) - .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); + .flat_map(move |(bt, b)| predicates_from_bound(self, bt, b, constness)); - from_ty_params.chain(from_where_clauses).collect() + from_ty_params.chain(from_where_clauses) } }