diff options
| author | bors <bors@rust-lang.org> | 2019-11-20 03:07:39 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-11-20 03:07:39 +0000 |
| commit | f50d6ea348c2dd7c2f76e35ecde6560d87bb98ec (patch) | |
| tree | 3ee8e88d65463afa48968ad77ffbb859586fb179 /src | |
| parent | 618b01f9fa0a6b4e7e2ce5b3409abe104b80c4a8 (diff) | |
| parent | 0207a15fa14c2c05e33acac1abd4604fce1f346a (diff) | |
| download | rust-f50d6ea348c2dd7c2f76e35ecde6560d87bb98ec.tar.gz rust-f50d6ea348c2dd7c2f76e35ecde6560d87bb98ec.zip | |
Auto merge of #66104 - yodaldevoid:generic-arg-disambiguation, r=petrochenkov
Generic arg disambiguation Using the tactic suggested by @petrochenkov in https://github.com/rust-lang/rust/issues/60804#issuecomment-516769465 and on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/generic.20argument.20disambiguation), this change checks type arguments to see if they are really incorrectly-parsed const arguments. it should be noted that `segments.len() == 1 && segments[0].arg.is_none()` was reduced to `segments.len() == 1` as suggested by @petrochenkov in [zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/generic.20argument.20disambiguation/near/177848002). This change allowed a few more existing tests to have their braces removed. There are a couple of "problems" with these changes that I should note. First, there was a regression in the error messages found in "src/test/ui/privacy-ns1.rs" and "src/test/ui/privacy-ns1.rs". Second, some braces were unable to be removed from "src/test/ui/const-generics/fn-const-param-infer.rs". Those on line 24 caused the statement to stop equating when removed, and those on line 20 cause a statement that should not equate to produce no error when removed. I have not looked further into any of these issues yet, though I would be willing to look into them before landing this. I simply wanted to get some other eyes on this before going further. Fixes #60804 cc @varkor @jplatte
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/hir/def.rs | 38 | ||||
| -rw-r--r-- | src/librustc/hir/lowering.rs | 61 | ||||
| -rw-r--r-- | src/librustc_resolve/late.rs | 46 | ||||
| -rw-r--r-- | src/librustc_resolve/lib.rs | 8 | ||||
| -rw-r--r-- | src/test/ui/const-generics/const-generic-array-wrapper.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/const-generics/fn-const-param-call.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/const-generics/fn-const-param-infer.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/const-generics/fn-const-param-infer.stderr | 12 | ||||
| -rw-r--r-- | src/test/ui/const-generics/impl-const-generic-struct.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/const-generics/raw-ptr-const-param-deref.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/privacy/privacy-ns1.rs | 3 | ||||
| -rw-r--r-- | src/test/ui/privacy/privacy-ns1.stderr | 44 | ||||
| -rw-r--r-- | src/test/ui/privacy/privacy-ns2.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/privacy/privacy-ns2.stderr | 75 |
15 files changed, 221 insertions, 98 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index a1ad11580db..231b054f974 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<Id> Res<Id> { _ => 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, + } + } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 12f6f66e96b..06a7a6bb301 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), diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 8d11c7224c7..f48df7faea2 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, '_> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8f6bb91f028..c49db39643b 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 } 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 adffe32d67a..56a58c582f6 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, const N: usize>([T; {N}]); +struct Foo<T, const N: usize>([T; N]); -impl<T, const N: usize> Foo<T, {N}> { +impl<T, const N: usize> Foo<T, N> { 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 84615386d29..cd4b19db353 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<const F: fn() -> u32>; -impl<const F: fn() -> u32> Wrapper<{F}> { +impl<const F: fn() -> u32> Wrapper<F> { fn call() -> u32 { F() } } fn main() { - assert_eq!(Wrapper::<{function}>::call(), 17); + assert_eq!(Wrapper::<function>::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 78fb10e8cb9..dc69fa9eea5 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<T>(val: T) -> bool { true } fn generic<T>(val: usize) -> bool { val != 1 } fn main() { - let _: Option<Checked<{not_one}>> = None; - let _: Checked<{not_one}> = Checked::<{not_one}>; - let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types + let _: Option<Checked<not_one>> = None; + let _: Checked<not_one> = Checked::<not_one>; + let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types - let _ = Checked::<{generic_arg}>; + let _ = Checked::<generic_arg>; let _ = Checked::<{generic_arg::<usize>}>; let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types - let _ = Checked::<{generic}>; //~ type annotations needed + let _ = Checked::<generic>; //~ type annotations needed let _ = Checked::<{generic::<u16>}>; let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>; let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ 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 de0916b26bf..e36bb824151 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<not_one> = Checked::<not_two>; + | ^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` | = note: expected type `Checked<not_one>` found type `Checked<not_two>` @@ -25,10 +25,10 @@ LL | let _ = Checked::<{generic_arg::<u32>}>; found type `fn(u32) -> bool {generic_arg::<u32>}` 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::<generic>; + | ^^^^^^^ 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 7a0c0f2be5d..87572e51e81 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<const X: u32>; -impl<const X: u32> S<{X}> { +impl<const X: u32> S<X> { 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 d26ab8be4c3..745dde3c287 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<const P: *const u32>; -impl<const P: *const u32> Const<{P}> { +impl<const P: *const u32> Const<P> { 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 1e064fbd970..7942631bb70 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, const N: usize>([T; N]); -impl<T: fmt::Debug, const N: usize> fmt::Debug for Array<T, {N}> { +impl<T: fmt::Debug, const N: usize> fmt::Debug for Array<T, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list().entries(self.0.iter()).finish() } diff --git a/src/test/ui/privacy/privacy-ns1.rs b/src/test/ui/privacy/privacy-ns1.rs index 3326b12ffa5..614375e5e51 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<Bar>; //~ ERROR expected type, found function `Bar` + let _x: Box<Bar>; //~ 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 3c766a33baa..45ca00f55ab 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<Bar>; - | ^^^ - | -help: a struct with a similar name exists - | -LL | let _x: Box<Baz>; - | ^^^ -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<Bar>; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns1.rs:35:13 + | +LL | let _x: Box<Bar>; + | ^^^^^^^^ 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 a2cc9e6aa95..0546de873f3 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<Bar>; //~ ERROR expected type, found function `Bar` + let _x : Box<Bar>; //~ 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<Bar>; //~ ERROR expected type, found function `Bar` + let _x: Box<Bar>; //~ 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 6f54259f918..2871573130a 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<Bar>; - | ^^^ 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<Bar>; - | ^^^ - | -help: a struct with a similar name exists - | -LL | let _x: Box<Baz>; - | ^^^ -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<Bar>; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns2.rs:41:14 + | +LL | let _x : Box<Bar>; + | ^^^^^^^^ 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<Bar>; + | ^^^ unexpected const argument + +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/privacy-ns2.rs:49:13 + | +LL | let _x: Box<Bar>; + | ^^^^^^^^ 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`. |
