From 041a612dad70dbcc69189773ee396fcb55bda4f5 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:22:00 -0500 Subject: [PATCH 1/6] resolve: Allow idents to resolve to primitives in the type namespace --- src/librustc_resolve/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8f6bb91f028c3..c49db39643bc7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1726,6 +1726,14 @@ impl<'a> Resolver<'a> { } } + if ns == TypeNS { + if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) { + let binding = (Res::PrimTy(*prim_ty), ty::Visibility::Public, + DUMMY_SP, ExpnId::root()).to_name_binding(self.arenas); + return Some(LexicalScopeBinding::Item(binding)); + } + } + None } From 128ca7415f970b13150e90b4705188d7f076d389 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:22:49 -0500 Subject: [PATCH 2/6] rustc: hir: Add method to check validity of a Res/Def in a namespace --- src/librustc/hir/def.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index a1ad11580dbb7..231b054f9748d 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -127,6 +127,34 @@ impl DefKind { _ => "a", } } + + pub fn matches_ns(&self, ns: Namespace) -> bool { + match self { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::AssocOpaqueTy + | DefKind::TyParam => ns == Namespace::TypeNS, + + DefKind::Fn + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static + | DefKind::Ctor(..) + | DefKind::Method + | DefKind::AssocConst => ns == Namespace::ValueNS, + + DefKind::Macro(..) => ns == Namespace::MacroNS, + } + } } #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)] @@ -427,4 +455,14 @@ impl Res { _ => None, } } + + pub fn matches_ns(&self, ns: Namespace) -> bool { + match self { + Res::Def(kind, ..) => kind.matches_ns(ns), + Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS, + Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS, + Res::NonMacroAttr(..) => ns == Namespace::MacroNS, + Res::Err => true, + } + } } From 7b4642f44178403770cc35166fb676b7fa051bec Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:24:13 -0500 Subject: [PATCH 3/6] resolve: late: Check if type arg is really a const arg A path type argument could be a generic const argument due to limitations as to what we can determine at parsing. We double check just to be sure by trying to resolve in the type namespace first, and if that fails we try again in the value namespace. If resolution in the value namespace succeeds, we have a generic const argument on our hands. --- src/librustc_resolve/late.rs | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 8d11c7224c704..f48df7faea25a 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -546,6 +546,52 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { self.visit_where_predicate(p); } } + + fn visit_generic_arg(&mut self, arg: &'tcx GenericArg) { + debug!("visit_generic_arg({:?})", arg); + match arg { + GenericArg::Type(ref ty) => { + // We parse const arguments as path types as we cannot distiguish them durring + // parsing. We try to resolve that ambiguity by attempting resolution the type + // namespace first, and if that fails we try again in the value namespace. If + // resolution in the value namespace succeeds, we have an generic const argument on + // our hands. + if let TyKind::Path(ref qself, ref path) = ty.kind { + // We cannot disambiguate multi-segment paths right now as that requires type + // checking. + if path.segments.len() == 1 && path.segments[0].args.is_none() { + let mut check_ns = |ns| self.resolve_ident_in_lexical_scope( + path.segments[0].ident, ns, None, path.span + ).is_some(); + + if !check_ns(TypeNS) && check_ns(ValueNS) { + // This must be equivalent to `visit_anon_const`, but we cannot call it + // directly due to visitor lifetimes so we have to copy-paste some code. + self.with_constant_rib(|this| { + this.smart_resolve_path( + ty.id, + qself.as_ref(), + path, + PathSource::Expr(None) + ); + + if let Some(ref qself) = *qself { + this.visit_ty(&qself.ty); + } + this.visit_path(path, ty.id); + }); + + return; + } + } + } + + self.visit_ty(ty); + } + GenericArg::Lifetime(lt) => self.visit_lifetime(lt), + GenericArg::Const(ct) => self.visit_anon_const(ct), + } + } } impl<'a, 'b> LateResolutionVisitor<'a, '_> { From fb6cfde5bad603193d1ae42786a725bd5dc01a40 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:30:01 -0500 Subject: [PATCH 4/6] rustc: lowering: Lower type args as const args when resolved in value namespace --- src/librustc/hir/lowering.rs | 61 +++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 12f6f66e96b50..06a7a6bb301de 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1155,13 +1155,64 @@ impl<'a> LoweringContext<'a> { } } - fn lower_generic_arg(&mut self, - arg: &ast::GenericArg, - itctx: ImplTraitContext<'_>) - -> hir::GenericArg { + fn lower_generic_arg( + &mut self, + arg: &ast::GenericArg, + itctx: ImplTraitContext<'_> + ) -> hir::GenericArg { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), - ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)), + ast::GenericArg::Type(ty) => { + // We parse const arguments as path types as we cannot distiguish them durring + // parsing. We try to resolve that ambiguity by attempting resolution in both the + // type and value namespaces. If we resolved the path in the value namespace, we + // transform it into a generic const argument. + if let TyKind::Path(ref qself, ref path) = ty.kind { + if let Some(partial_res) = self.resolver.get_partial_res(ty.id) { + let res = partial_res.base_res(); + if !res.matches_ns(Namespace::TypeNS) { + debug!( + "lower_generic_arg: Lowering type argument as const argument: {:?}", + ty, + ); + + // Construct a AnonConst where the expr is the "ty"'s path. + + let parent_def_index = + self.current_hir_id_owner.last().unwrap().0; + let node_id = self.resolver.next_node_id(); + + // Add a definition for the in-band const def. + self.resolver.definitions().create_def_with_parent( + parent_def_index, + node_id, + DefPathData::AnonConst, + ExpnId::root(), + ty.span, + ); + + let path_expr = Expr { + id: ty.id, + kind: ExprKind::Path(qself.clone(), path.clone()), + span: ty.span, + attrs: ThinVec::new(), + }; + + let ct = self.with_new_scopes(|this| { + hir::AnonConst { + hir_id: this.lower_node_id(node_id), + body: this.lower_const_body(&path_expr), + } + }); + return GenericArg::Const(ConstArg { + value: ct, + span: ty.span, + }); + } + } + } + GenericArg::Type(self.lower_ty_direct(&ty, itctx)) + } ast::GenericArg::Const(ct) => { GenericArg::Const(ConstArg { value: self.lower_anon_const(&ct), From eaf8fd056942cd8da2d5d5c844bba145b95f6d1a Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:57:23 -0500 Subject: [PATCH 5/6] test: const-generics: Update tests removing unrequired braces Braces were left in cases where generic args were in the generic const paths. --- .../ui/const-generics/const-generic-array-wrapper.rs | 6 +++--- src/test/ui/const-generics/fn-const-param-call.rs | 4 ++-- src/test/ui/const-generics/fn-const-param-infer.rs | 10 +++++----- .../ui/const-generics/fn-const-param-infer.stderr | 12 ++++++------ .../ui/const-generics/impl-const-generic-struct.rs | 2 +- .../ui/const-generics/raw-ptr-const-param-deref.rs | 2 +- .../uninferred-consts-during-codegen-1.rs | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/test/ui/const-generics/const-generic-array-wrapper.rs b/src/test/ui/const-generics/const-generic-array-wrapper.rs index adffe32d67a30..56a58c582f645 100644 --- a/src/test/ui/const-generics/const-generic-array-wrapper.rs +++ b/src/test/ui/const-generics/const-generic-array-wrapper.rs @@ -3,11 +3,11 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -struct Foo([T; {N}]); +struct Foo([T; N]); -impl Foo { +impl Foo { fn foo(&self) -> usize { - {N} + N } } diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs index 84615386d2995..cd4b19db35331 100644 --- a/src/test/ui/const-generics/fn-const-param-call.rs +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -9,12 +9,12 @@ fn function() -> u32 { struct Wrapper u32>; -impl u32> Wrapper<{F}> { +impl u32> Wrapper { fn call() -> u32 { F() } } fn main() { - assert_eq!(Wrapper::<{function}>::call(), 17); + assert_eq!(Wrapper::::call(), 17); } diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs index 78fb10e8cb904..dc69fa9eea585 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.rs +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -11,15 +11,15 @@ fn generic_arg(val: T) -> bool { true } fn generic(val: usize) -> bool { val != 1 } fn main() { - let _: Option> = None; - let _: Checked<{not_one}> = Checked::<{not_one}>; - let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types + let _: Option> = None; + let _: Checked = Checked::; + let _: Checked = Checked::; //~ mismatched types - let _ = Checked::<{generic_arg}>; + let _ = Checked::; let _ = Checked::<{generic_arg::}>; let _ = Checked::<{generic_arg::}>; //~ mismatched types - let _ = Checked::<{generic}>; //~ type annotations needed + let _ = Checked::; //~ type annotations needed let _ = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index de0916b26bfef..e36bb824151f7 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -7,10 +7,10 @@ LL | #![feature(const_generics, const_compare_raw_pointers)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:16:33 + --> $DIR/fn-const-param-infer.rs:16:31 | -LL | let _: Checked<{not_one}> = Checked::<{not_two}>; - | ^^^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` +LL | let _: Checked = Checked::; + | ^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` | = note: expected type `Checked` found type `Checked` @@ -25,10 +25,10 @@ LL | let _ = Checked::<{generic_arg::}>; found type `fn(u32) -> bool {generic_arg::}` error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:22:24 + --> $DIR/fn-const-param-infer.rs:22:23 | -LL | let _ = Checked::<{generic}>; - | ^^^^^^^ cannot infer type for `T` +LL | let _ = Checked::; + | ^^^^^^^ cannot infer type for `T` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 diff --git a/src/test/ui/const-generics/impl-const-generic-struct.rs b/src/test/ui/const-generics/impl-const-generic-struct.rs index 7a0c0f2be5d7a..87572e51e8142 100644 --- a/src/test/ui/const-generics/impl-const-generic-struct.rs +++ b/src/test/ui/const-generics/impl-const-generic-struct.rs @@ -5,7 +5,7 @@ struct S; -impl S<{X}> { +impl S { fn x() -> u32 { X } diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs index d26ab8be4c3fe..745dde3c28766 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -6,7 +6,7 @@ const A: u32 = 3; struct Const; -impl Const<{P}> { +impl Const

{ fn get() -> u32 { unsafe { *P diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs index 1e064fbd97064..7942631bb70b9 100644 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs @@ -7,7 +7,7 @@ use std::fmt; struct Array([T; N]); -impl fmt::Debug for Array { +impl fmt::Debug for Array { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list().entries(self.0.iter()).finish() } From 0207a15fa14c2c05e33acac1abd4604fce1f346a Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 18 Nov 2019 14:57:46 -0500 Subject: [PATCH 6/6] test: Update tests with fallout of changes The error messages of the two tests effected degraded in quality. The errors no longer suggest types in other modules as they now assume that the arguments are const args, not type args. --- src/test/ui/privacy/privacy-ns1.rs | 3 +- src/test/ui/privacy/privacy-ns1.stderr | 44 ++++++--------- src/test/ui/privacy/privacy-ns2.rs | 6 ++- src/test/ui/privacy/privacy-ns2.stderr | 75 +++++++++++--------------- 4 files changed, 54 insertions(+), 74 deletions(-) diff --git a/src/test/ui/privacy/privacy-ns1.rs b/src/test/ui/privacy/privacy-ns1.rs index 3326b12ffa535..614375e5e51d5 100644 --- a/src/test/ui/privacy/privacy-ns1.rs +++ b/src/test/ui/privacy/privacy-ns1.rs @@ -32,7 +32,8 @@ pub mod foo2 { fn test_glob2() { use foo2::*; - let _x: Box; //~ ERROR expected type, found function `Bar` + let _x: Box; //~ ERROR wrong number of const arguments: expected 0, found 1 + //~^ ERROR wrong number of type arguments: expected 1, found 0 } // neither public diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr index 3c766a33baae8..45ca00f55ab59 100644 --- a/src/test/ui/privacy/privacy-ns1.stderr +++ b/src/test/ui/privacy/privacy-ns1.stderr @@ -20,30 +20,8 @@ LL | use foo2::Bar; LL | use foo3::Bar; | -error[E0573]: expected type, found function `Bar` - --> $DIR/privacy-ns1.rs:35:17 - | -LL | pub struct Baz; - | --------------- similarly named struct `Baz` defined here -... -LL | let _x: Box; - | ^^^ - | -help: a struct with a similar name exists - | -LL | let _x: Box; - | ^^^ -help: possible better candidates are found in other modules, you can import them into scope - | -LL | use foo1::Bar; - | -LL | use foo2::Bar; - | -LL | use foo3::Bar; - | - error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope - --> $DIR/privacy-ns1.rs:50:5 + --> $DIR/privacy-ns1.rs:51:5 | LL | pub struct Baz; | --------------- similarly named unit struct `Baz` defined here @@ -65,7 +43,7 @@ LL | use foo3::Bar; | error[E0412]: cannot find type `Bar` in this scope - --> $DIR/privacy-ns1.rs:51:17 + --> $DIR/privacy-ns1.rs:52:17 | LL | pub struct Baz; | --------------- similarly named struct `Baz` defined here @@ -86,7 +64,19 @@ LL | use foo2::Bar; LL | use foo3::Bar; | -error: aborting due to 4 previous errors +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/privacy-ns1.rs:35:17 + | +LL | let _x: Box; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns1.rs:35:13 + | +LL | let _x: Box; + | ^^^^^^^^ expected 1 type argument + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0412, E0423, E0425, E0573. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0107, E0412, E0423, E0425. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/privacy/privacy-ns2.rs b/src/test/ui/privacy/privacy-ns2.rs index a2cc9e6aa9515..0546de873f340 100644 --- a/src/test/ui/privacy/privacy-ns2.rs +++ b/src/test/ui/privacy/privacy-ns2.rs @@ -38,14 +38,16 @@ pub mod foo2 { fn test_single2() { use foo2::Bar; - let _x : Box; //~ ERROR expected type, found function `Bar` + let _x : Box; //~ ERROR wrong number of const arguments: expected 0, found 1 + //~^ ERROR wrong number of type arguments: expected 1, found 0 let _x : Bar(); //~ ERROR expected type, found function `Bar` } fn test_list2() { use foo2::{Bar,Baz}; - let _x: Box; //~ ERROR expected type, found function `Bar` + let _x: Box; //~ ERROR wrong number of const arguments: expected 0, found 1 + //~^ ERROR wrong number of type arguments: expected 1, found 0 } // neither public diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr index 6f54259f91867..2871573130a60 100644 --- a/src/test/ui/privacy/privacy-ns2.stderr +++ b/src/test/ui/privacy/privacy-ns2.stderr @@ -36,22 +36,7 @@ LL | use foo3::Bar; | error[E0573]: expected type, found function `Bar` - --> $DIR/privacy-ns2.rs:41:18 - | -LL | let _x : Box; - | ^^^ not a type - | -help: possible better candidates are found in other modules, you can import them into scope - | -LL | use foo1::Bar; - | -LL | use foo2::Bar; - | -LL | use foo3::Bar; - | - -error[E0573]: expected type, found function `Bar` - --> $DIR/privacy-ns2.rs:42:14 + --> $DIR/privacy-ns2.rs:43:14 | LL | let _x : Bar(); | ^^^^^ not a type @@ -69,47 +54,49 @@ LL | use foo2::Bar; LL | use foo3::Bar; | -error[E0573]: expected type, found function `Bar` - --> $DIR/privacy-ns2.rs:48:17 - | -LL | pub struct Baz; - | --------------- similarly named struct `Baz` defined here -... -LL | let _x: Box; - | ^^^ - | -help: a struct with a similar name exists - | -LL | let _x: Box; - | ^^^ -help: possible better candidates are found in other modules, you can import them into scope - | -LL | use foo1::Bar; - | -LL | use foo2::Bar; - | -LL | use foo3::Bar; - | - error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:61:15 + --> $DIR/privacy-ns2.rs:63:15 | LL | use foo3::Bar; | ^^^ error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:65:15 + --> $DIR/privacy-ns2.rs:67:15 | LL | use foo3::Bar; | ^^^ error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:72:16 + --> $DIR/privacy-ns2.rs:74:16 | LL | use foo3::{Bar,Baz}; | ^^^ -error: aborting due to 8 previous errors +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/privacy-ns2.rs:41:18 + | +LL | let _x : Box; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns2.rs:41:14 + | +LL | let _x : Box; + | ^^^^^^^^ expected 1 type argument + +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/privacy-ns2.rs:49:17 + | +LL | let _x: Box; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns2.rs:49:13 + | +LL | let _x: Box; + | ^^^^^^^^ expected 1 type argument + +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0423, E0573, E0603. -For more information about an error, try `rustc --explain E0423`. +Some errors have detailed explanations: E0107, E0423, E0573, E0603. +For more information about an error, try `rustc --explain E0107`.