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 8f6bb91f028c..c49db39643bc 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 a1ad11580dbb..231b054f9748 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 8d11c7224c70..f48df7faea25 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 12f6f66e96b5..06a7a6bb301d 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 adffe32d67a3..56a58c582f64 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 84615386d299..cd4b19db3533 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 78fb10e8cb90..dc69fa9eea58 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 de0916b26bfe..e36bb824151f 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 7a0c0f2be5d7..87572e51e814 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 d26ab8be4c3f..745dde3c2876 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 1e064fbd9706..7942631bb70b 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 3326b12ffa53..614375e5e51d 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 3c766a33baae..45ca00f55ab5 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 -Some errors have detailed explanations: E0412, E0423, E0425, E0573. -For more information about an error, try `rustc --explain E0412`. +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: 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 a2cc9e6aa951..0546de873f34 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 6f54259f9186..2871573130a6 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 -Some errors have detailed explanations: E0423, E0573, E0603. -For more information about an error, try `rustc --explain E0423`. +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: E0107, E0423, E0573, E0603. +For more information about an error, try `rustc --explain E0107`.