1
Fork 0

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
This commit is contained in:
bors 2019-11-20 03:07:39 +00:00
commit f50d6ea348
15 changed files with 221 additions and 98 deletions

View file

@ -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,
}
}
}

View file

@ -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(&lt)),
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),

View file

@ -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, '_> {

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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()
}

View file

@ -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

View file

@ -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
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<Bar>;
| ^^^^^^^^ 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`.

View file

@ -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

View file

@ -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
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<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: E0107, E0423, E0573, E0603.
For more information about an error, try `rustc --explain E0107`.