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, 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/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 a3a2b8967c606..97295ce0b1ec3 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,396 +16,383 @@ 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 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 }, - 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. +/// 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` + ) +} - if position != GenericArgPosition::Type && !args.bindings.is_empty() { - AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); - } +/// 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() { + 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 @@ -472,143 +459,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..60e5b622ae3a1 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, @@ -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) } } @@ -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,