Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
surechen committed Sep 26, 2023
1 parent 0a689c1 commit 053aecf
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 6 deletions.
44 changes: 43 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// struct Foo<const N: usize = { .. }>;
// ^^^ ^ ^^^^^^ 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])`.
Expand All @@ -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<T>() where for<const N: u8 = { T::<0>::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(&param_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[&param_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();
Expand Down
35 changes: 30 additions & 5 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ enum Scope<'a> {
/// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
/// ```
where_bound_origin: Option<hir::PredicateOrigin>,
in_where_predict: bool,
},

/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -478,14 +480,14 @@ 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,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
in_where_predict: false,
};

self.with(scope, |this| {
Expand Down Expand Up @@ -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 };
Expand Down Expand Up @@ -630,14 +633,14 @@ 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,
bound_vars,
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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -963,14 +967,14 @@ 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,
bound_vars: FxIndexMap::default(),
s: self.scope,
scope_type,
where_bound_origin: None,
in_where_predict: false,
};
self.with(scope, |this| {
intravisit::walk_param_bound(this, bound);
Expand All @@ -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<T>() where for<const N: u8 = { T::<0>::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);
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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 };
Expand Down Expand Up @@ -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, .. } => {
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/traits/issue-115497.rs
Original file line number Diff line number Diff line change
@@ -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<T>() where for<const N: u8 = { T::<0>::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() {}
43 changes: 43 additions & 0 deletions tests/ui/traits/issue-115497.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/108185> for more information

error[E0109]: const arguments are not allowed on type parameter `T`
--> $DIR/issue-115497.rs:6:43
|
LL | fn foo<T>() where for<const N: u8 = { T::<0>::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<T>() where for<const N: u8 = { T::<0>::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<T>() where for<const N: u8 = { T::<0>::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`.

0 comments on commit 053aecf

Please sign in to comment.