diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 3d60c57b9d5ad..a4c65f90e4699 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -65,7 +65,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // struct Foo; // ^^^ ^ ^^^^^^ def id of this anon const // ^ ^ param_id - // ^ parent_def_id + // ^ parent_def_id after // // then we only want to return generics for params to the left of `N`. If we don't do that we // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`. @@ -85,6 +85,48 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // This has some implications for how we get the predicates available to the anon const // see `explicit_predicates_of` for more information on this let generics = tcx.generics_of(parent_def_id.to_def_id()); + let parent_node = tcx.hir().get_parent(hir_id); + + // For expr in where predict. + // Will panic If we directly obtain GenericParamDef from the generics params based on the index. + // fn foo() where for::A as u8 }> T: Default {} + // ^^^^^^^^^^^^^^^^^^^ hir_id + // ^ param_id + // ^^^ parent_id after twice iterations + // ^ generics of parent + // Push GenericParamDef of 'N' in above example into params. + if let hir::Node::GenericParam( + GenericParam{ + hir_id: parent_hir_id, + kind: GenericParamKind::Const { + ty: ty_info, + default: Some(anon_const) }, + name, + def_id, + pure_wrt_drop, ..}) = parent_node + && !generics.param_def_id_to_index.contains_key(¶m_id.to_def_id()) + && anon_const.hir_id == hir_id { + let mut params = generics.params.to_vec(); + params.push(ty::GenericParamDef { + name: name.ident().name, + index: (params.len() + 1) as u32, + def_id: def_id.to_def_id(), + pure_wrt_drop: *pure_wrt_drop, + kind: ty::GenericParamDefKind::Lifetime, + }); + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + return ty::Generics { + parent: generics.parent, + parent_count: generics.parent_count, + params, + param_def_id_to_index, + has_self: generics.has_self, + has_late_bound_regions: generics.has_late_bound_regions, + host_effect_index: None, + }; + } let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()]; // In the above example this would be .params[..N#0] let params = generics.params_to(param_def_idx as usize, tcx).to_owned(); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6869c86960380..e9aac2bfbc86a 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -126,6 +126,7 @@ enum Scope<'a> { /// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} /// ``` where_bound_origin: Option, + in_where_predict: bool, }, /// Lifetimes introduced by a fn are scoped to the call-site for that fn, @@ -195,7 +196,7 @@ struct TruncatedScopeDebug<'a>(&'a Scope<'a>); impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { - Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f + Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _, .. } => f .debug_struct("Binder") .field("bound_vars", bound_vars) .field("scope_type", scope_type) @@ -394,6 +395,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { s: self.scope, scope_type, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, |this| { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); @@ -478,7 +480,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .unzip(); deny_non_region_late_bound(self.tcx, &mut bound_vars, "closures"); - self.record_late_bound_vars(e.hir_id, binders); let scope = Scope::Binder { hir_id: e.hir_id, @@ -486,6 +487,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { s: self.scope, scope_type: BinderScopeType::Normal, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, |this| { @@ -577,6 +579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { s: this.scope, scope_type: BinderScopeType::Normal, where_bound_origin: None, + in_where_predict: false, }; this.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -630,7 +633,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .unzip(); deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types"); - self.record_late_bound_vars(ty.hir_id, binders); let scope = Scope::Binder { hir_id: ty.hir_id, @@ -638,6 +640,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { s: self.scope, scope_type: BinderScopeType::Normal, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, |this| { // a bare fn has no bounds, so everything @@ -907,6 +910,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { s: self.scope, scope_type: BinderScopeType::Normal, where_bound_origin: Some(origin), + in_where_predict: true, }; self.with(scope, |this| { walk_list!(this, visit_generic_param, bound_generic_params); @@ -963,7 +967,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // of "if there isn't a Binder scope above us, add one", but I // imagine there's a better way to go about this. let (binders, scope_type) = self.poly_trait_ref_binder_info(); - self.record_late_bound_vars(*hir_id, binders); let scope = Scope::Binder { hir_id: *hir_id, @@ -971,6 +974,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { s: self.scope, scope_type, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, |this| { intravisit::walk_param_bound(this, bound); @@ -992,6 +996,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { match p.kind { + GenericParamKind::Const { ty, default: Some(default) } => { + self.resolve_type_ref(p.def_id, p.hir_id); + + // For expr in default of Const expr in where predict. + // We may get unexpected bound var resolution when converts a hir id + // corresponding to a type parameter to a early-bound `ty::Param` or late-bound `ty::Bound` + // fn foo() where for::A as u8 }> T: Default {} + // ^ generic param ty + // ^^^^^^ hir_id + // ^^^^^^^^^^^^^^^^^^^ default + // ^^^ parent_id after twice iterations + // ^ generics of parent + if let Scope::Binder {in_where_predict, .. } = self.scope && *in_where_predict { + let BoundVarContext { tcx, map, .. } = self; + let wrap_scope = Scope::LateBoundary { s: self.scope, what: "constant" }; + let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope }; + this.visit_id(default.hir_id); + this.visit_nested_body(default.body); + } + } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { self.resolve_type_ref(p.def_id, p.hir_id); } @@ -1144,6 +1168,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { s: self.scope, scope_type: BinderScopeType::Normal, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, walk); } @@ -1160,6 +1185,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { s: self.scope, scope_type: BinderScopeType::Normal, where_bound_origin: None, + in_where_predict: false, }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -1369,7 +1395,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; let mut crossed_late_boundary = None; - let result = loop { match *scope { Scope::Body { s, .. } => { diff --git a/tests/ui/traits/issue-115497.rs b/tests/ui/traits/issue-115497.rs new file mode 100644 index 0000000000000..2a7a09dcfcb32 --- /dev/null +++ b/tests/ui/traits/issue-115497.rs @@ -0,0 +1,10 @@ +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn foo() where for::A as u8 }> T: Default {} +//~^ ERROR const arguments are not allowed on type parameter `T` +//~| ERROR no associated item named `A` found for type parameter `T` in the current scope + +fn main() {} diff --git a/tests/ui/traits/issue-115497.stderr b/tests/ui/traits/issue-115497.stderr new file mode 100644 index 0000000000000..f1a5a7218987f --- /dev/null +++ b/tests/ui/traits/issue-115497.stderr @@ -0,0 +1,43 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-115497.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-115497.rs:3:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + +error[E0109]: const arguments are not allowed on type parameter `T` + --> $DIR/issue-115497.rs:6:43 + | +LL | fn foo() where for::A as u8 }> T: Default {} + | - ^ const argument not allowed + | | + | not allowed on type parameter `T` + | +note: type parameter `T` defined here + --> $DIR/issue-115497.rs:6:8 + | +LL | fn foo() where for::A as u8 }> T: Default {} + | ^ + +error[E0599]: no associated item named `A` found for type parameter `T` in the current scope + --> $DIR/issue-115497.rs:6:47 + | +LL | fn foo() where for::A as u8 }> T: Default {} + | - ^ associated item not found in `T` + | | + | associated item `A` not found for this type parameter + +error: aborting due to 2 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0109, E0599. +For more information about an error, try `rustc --explain E0109`.