From 1d9ac3c22c98b468eb3d6c9770f1ab4be782dc74 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 9 Feb 2021 08:57:42 +0000 Subject: [PATCH 1/5] Fix const generics in GAT --- compiler/rustc_typeck/src/collect/type_of.rs | 42 +++++++++++++++++++ compiler/rustc_typeck/src/lib.rs | 1 + ...nst-generics-gat-in-trait-return-type-1.rs | 22 ++++++++++ ...nst-generics-gat-in-trait-return-type-2.rs | 22 ++++++++++ ...nst-generics-gat-in-trait-return-type-3.rs | 27 ++++++++++++ 5 files changed, 114 insertions(+) create mode 100644 src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs create mode 100644 src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs create mode 100644 src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index e4eabca9c3b76..ef17ab9ccd137 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -29,6 +29,48 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let parent_node = tcx.hir().get(parent_node_id); match parent_node { + Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + let id = tcx + .hir() + .parent_iter(hir_id) + .filter(|(_, node)| matches!(node, Node::Item(_))) + .map(|(id, _)| id) + .next() + .unwrap(); + + let item_did = tcx.hir().local_def_id(id).to_def_id(); + let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; + let ty = item_ctxt.ast_ty_to_ty(hir_ty); + + if let ty::Projection(projection) = ty.kind() { + let generics = tcx.generics_of(projection.item_def_id); + + let arg_index = segment + .args + .and_then(|args| { + args.args + .iter() + .filter(|arg| arg.is_const()) + .position(|arg| arg.id() == hir_id) + }) + .unwrap_or_else(|| { + bug!("no arg matching AnonConst in segment"); + }); + + return generics + .params + .iter() + .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const)) + .nth(arg_index) + .map(|param| param.def_id); + } + + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "unexpected non-GAT usage of an anon const", + ); + return None; + } Node::Expr(&Expr { kind: ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)), diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index fd44bafab6f76..2284767debb4d 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -56,6 +56,7 @@ This API is completely unstable and subject to change. */ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs new file mode 100644 index 0000000000000..ab33ef6f2442c --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs @@ -0,0 +1,22 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Foo::Assoc GAT. + +trait Foo { + type Assoc; + fn foo(&self) -> Self::Assoc<3>; +} + +impl Foo for () { + type Assoc = [(); N]; + fn foo(&self) -> Self::Assoc<3> { + [(); 3] + } +} + +fn main() { + assert_eq!(().foo(), [(); 3]); +} diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs new file mode 100644 index 0000000000000..ba9a82ae72109 --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs @@ -0,0 +1,22 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Foo::Assoc GAT. + +trait Foo { + type Assoc; + fn foo(&self) -> Self::Assoc; +} + +impl Foo for () { + type Assoc = [(); N]; + fn foo(&self) -> Self::Assoc { + [(); N] + } +} + +fn main() { + assert_eq!(().foo::<10>(), [(); 10]); +} diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs new file mode 100644 index 0000000000000..9da5334056a37 --- /dev/null +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs @@ -0,0 +1,27 @@ +// run-pass +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +// This test unsures that with_opt_const_param returns the +// def_id of the N param in the Bar::Assoc GAT. + +trait Bar { + type Assoc; +} +trait Foo: Bar { + fn foo(&self) -> Self::Assoc<3>; +} + +impl Bar for () { + type Assoc = [(); N]; +} + +impl Foo for () { + fn foo(&self) -> Self::Assoc<3> { + [(); 3] + } +} + +fn main() { + assert_eq!(().foo(), [(); 3]); +} From 2c4337a70a4d4451fc440b1bb60ff5ca8b7eb5b2 Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 10 Feb 2021 05:15:35 +0000 Subject: [PATCH 2/5] Comments :3 --- compiler/rustc_typeck/src/collect/type_of.rs | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index ef17ab9ccd137..b5f37c8398ef3 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -29,19 +29,32 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let parent_node = tcx.hir().get(parent_node_id); match parent_node { + // This matches on types who's paths couldn't be resolved without typeck'ing e.g. + // + // trait Foo { + // type Assoc;; + // fn foo() -> Self::Assoc<3>; + // // note: if the def_id argument is the 3 then in this example + // // parent_node would be the node for Self::Assoc<_> + // } + // We didnt write ::Assoc so the Self::Assoc<_> is lowered to QPath::TypeRelative. + // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { - let id = tcx + // Walk up from the parent_node to find an item so that + // we can resolve the relative path to an actual associated type + let item_hir_id = tcx .hir() .parent_iter(hir_id) .filter(|(_, node)| matches!(node, Node::Item(_))) .map(|(id, _)| id) .next() .unwrap(); - - let item_did = tcx.hir().local_def_id(id).to_def_id(); + let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id(); let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; - let ty = item_ctxt.ast_ty_to_ty(hir_ty); + // This ty will be the actual associated type so that we can + // go through its generics to find which param our def_id corresponds to + let ty = item_ctxt.ast_ty_to_ty(hir_ty); if let ty::Projection(projection) = ty.kind() { let generics = tcx.generics_of(projection.item_def_id); @@ -65,6 +78,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< .map(|param| param.def_id); } + // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU tcx.sess.delay_span_bug( tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", From 042274558563623b7656df0a413bd3ccaf83678d Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 10 Feb 2021 05:23:02 +0000 Subject: [PATCH 3/5] Fix comment smol mistakes --- compiler/rustc_typeck/src/collect/type_of.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index b5f37c8398ef3..c2c9984f2afb9 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -32,7 +32,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // This matches on types who's paths couldn't be resolved without typeck'ing e.g. // // trait Foo { - // type Assoc;; + // type Assoc; // fn foo() -> Self::Assoc<3>; // // note: if the def_id argument is the 3 then in this example // // parent_node would be the node for Self::Assoc<_> @@ -41,7 +41,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Walk up from the parent_node to find an item so that - // we can resolve the relative path to an actual associated type + // we can resolve the relative path to an actual associated type. + // For the code example above this item would be the Foo trait. let item_hir_id = tcx .hir() .parent_iter(hir_id) @@ -53,7 +54,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; // This ty will be the actual associated type so that we can - // go through its generics to find which param our def_id corresponds to + // go through its generics to find which param our def_id corresponds to. + // For the code example above, this ty would be the Assoc. let ty = item_ctxt.ast_ty_to_ty(hir_ty); if let ty::Projection(projection) = ty.kind() { let generics = tcx.generics_of(projection.item_def_id); From 0ffa2da18648afa75f272dfbd0182232c2ca87c1 Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 10 Feb 2021 05:29:45 +0000 Subject: [PATCH 4/5] comma... --- compiler/rustc_typeck/src/collect/type_of.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index c2c9984f2afb9..571b91cf25446 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -42,7 +42,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Walk up from the parent_node to find an item so that // we can resolve the relative path to an actual associated type. - // For the code example above this item would be the Foo trait. + // For the code example above, this item would be the Foo trait. let item_hir_id = tcx .hir() .parent_iter(hir_id) From 7ca96ed2af7552cf67be36befe8f6e25e5fe63f8 Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 10 Feb 2021 13:11:12 +0000 Subject: [PATCH 5/5] rewrite the comments --- compiler/rustc_typeck/src/collect/type_of.rs | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 571b91cf25446..7fa58dcd5f44f 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -29,20 +29,28 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let parent_node = tcx.hir().get(parent_node_id); match parent_node { - // This matches on types who's paths couldn't be resolved without typeck'ing e.g. + // This match arm is for when the def_id appears in a GAT whose + // path can't be resolved without typechecking e.g. // // trait Foo { - // type Assoc; + // type Assoc; // fn foo() -> Self::Assoc<3>; - // // note: if the def_id argument is the 3 then in this example - // // parent_node would be the node for Self::Assoc<_> // } - // We didnt write ::Assoc so the Self::Assoc<_> is lowered to QPath::TypeRelative. + // + // In the above code we would call this query with the def_id of 3 and + // the parent_node we match on would be the hir node for Self::Assoc<3> + // + // `Self::Assoc<3>` cant be resolved without typchecking here as we + // didnt write ::Assoc<3>. If we did then another match + // arm would handle this. + // // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { - // Walk up from the parent_node to find an item so that - // we can resolve the relative path to an actual associated type. - // For the code example above, this item would be the Foo trait. + // Find the Item containing the associated type so we can create an ItemCtxt. + // Using the ItemCtxt convert the HIR for the unresolved assoc type into a + // ty which is a fully resolved projection. + // For the code example above, this would mean converting Self::Assoc<3> + // into a ty::Projection(::Assoc<3>) let item_hir_id = tcx .hir() .parent_iter(hir_id) @@ -52,11 +60,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< .unwrap(); let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id(); let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; - - // This ty will be the actual associated type so that we can - // go through its generics to find which param our def_id corresponds to. - // For the code example above, this ty would be the Assoc. let ty = item_ctxt.ast_ty_to_ty(hir_ty); + + // Iterate through the generics of the projection to find the one that corresponds to + // the def_id that this query was called with. We filter to only const args here as a + // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't + // but it can't hurt to be safe ^^ if let ty::Projection(projection) = ty.kind() { let generics = tcx.generics_of(projection.item_def_id);