Skip to content

Commit f50d6ea

Browse files
committed
Auto merge of #66104 - yodaldevoid:generic-arg-disambiguation, r=petrochenkov
Generic arg disambiguation Using the tactic suggested by @petrochenkov in #60804 (comment) 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
2 parents 618b01f + 0207a15 commit f50d6ea

15 files changed

+221
-98
lines changed

src/librustc/hir/def.rs

+38
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,34 @@ impl DefKind {
127127
_ => "a",
128128
}
129129
}
130+
131+
pub fn matches_ns(&self, ns: Namespace) -> bool {
132+
match self {
133+
DefKind::Mod
134+
| DefKind::Struct
135+
| DefKind::Union
136+
| DefKind::Enum
137+
| DefKind::Variant
138+
| DefKind::Trait
139+
| DefKind::OpaqueTy
140+
| DefKind::TyAlias
141+
| DefKind::ForeignTy
142+
| DefKind::TraitAlias
143+
| DefKind::AssocTy
144+
| DefKind::AssocOpaqueTy
145+
| DefKind::TyParam => ns == Namespace::TypeNS,
146+
147+
DefKind::Fn
148+
| DefKind::Const
149+
| DefKind::ConstParam
150+
| DefKind::Static
151+
| DefKind::Ctor(..)
152+
| DefKind::Method
153+
| DefKind::AssocConst => ns == Namespace::ValueNS,
154+
155+
DefKind::Macro(..) => ns == Namespace::MacroNS,
156+
}
157+
}
130158
}
131159

132160
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)]
@@ -427,4 +455,14 @@ impl<Id> Res<Id> {
427455
_ => None,
428456
}
429457
}
458+
459+
pub fn matches_ns(&self, ns: Namespace) -> bool {
460+
match self {
461+
Res::Def(kind, ..) => kind.matches_ns(ns),
462+
Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS,
463+
Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS,
464+
Res::NonMacroAttr(..) => ns == Namespace::MacroNS,
465+
Res::Err => true,
466+
}
467+
}
430468
}

src/librustc/hir/lowering.rs

+56-5
Original file line numberDiff line numberDiff line change
@@ -1155,13 +1155,64 @@ impl<'a> LoweringContext<'a> {
11551155
}
11561156
}
11571157

1158-
fn lower_generic_arg(&mut self,
1159-
arg: &ast::GenericArg,
1160-
itctx: ImplTraitContext<'_>)
1161-
-> hir::GenericArg {
1158+
fn lower_generic_arg(
1159+
&mut self,
1160+
arg: &ast::GenericArg,
1161+
itctx: ImplTraitContext<'_>
1162+
) -> hir::GenericArg {
11621163
match arg {
11631164
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
1164-
ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
1165+
ast::GenericArg::Type(ty) => {
1166+
// We parse const arguments as path types as we cannot distiguish them durring
1167+
// parsing. We try to resolve that ambiguity by attempting resolution in both the
1168+
// type and value namespaces. If we resolved the path in the value namespace, we
1169+
// transform it into a generic const argument.
1170+
if let TyKind::Path(ref qself, ref path) = ty.kind {
1171+
if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
1172+
let res = partial_res.base_res();
1173+
if !res.matches_ns(Namespace::TypeNS) {
1174+
debug!(
1175+
"lower_generic_arg: Lowering type argument as const argument: {:?}",
1176+
ty,
1177+
);
1178+
1179+
// Construct a AnonConst where the expr is the "ty"'s path.
1180+
1181+
let parent_def_index =
1182+
self.current_hir_id_owner.last().unwrap().0;
1183+
let node_id = self.resolver.next_node_id();
1184+
1185+
// Add a definition for the in-band const def.
1186+
self.resolver.definitions().create_def_with_parent(
1187+
parent_def_index,
1188+
node_id,
1189+
DefPathData::AnonConst,
1190+
ExpnId::root(),
1191+
ty.span,
1192+
);
1193+
1194+
let path_expr = Expr {
1195+
id: ty.id,
1196+
kind: ExprKind::Path(qself.clone(), path.clone()),
1197+
span: ty.span,
1198+
attrs: ThinVec::new(),
1199+
};
1200+
1201+
let ct = self.with_new_scopes(|this| {
1202+
hir::AnonConst {
1203+
hir_id: this.lower_node_id(node_id),
1204+
body: this.lower_const_body(&path_expr),
1205+
}
1206+
});
1207+
return GenericArg::Const(ConstArg {
1208+
value: ct,
1209+
span: ty.span,
1210+
});
1211+
}
1212+
}
1213+
}
1214+
GenericArg::Type(self.lower_ty_direct(&ty, itctx))
1215+
}
11651216
ast::GenericArg::Const(ct) => {
11661217
GenericArg::Const(ConstArg {
11671218
value: self.lower_anon_const(&ct),

src/librustc_resolve/late.rs

+46
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,52 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
546546
self.visit_where_predicate(p);
547547
}
548548
}
549+
550+
fn visit_generic_arg(&mut self, arg: &'tcx GenericArg) {
551+
debug!("visit_generic_arg({:?})", arg);
552+
match arg {
553+
GenericArg::Type(ref ty) => {
554+
// We parse const arguments as path types as we cannot distiguish them durring
555+
// parsing. We try to resolve that ambiguity by attempting resolution the type
556+
// namespace first, and if that fails we try again in the value namespace. If
557+
// resolution in the value namespace succeeds, we have an generic const argument on
558+
// our hands.
559+
if let TyKind::Path(ref qself, ref path) = ty.kind {
560+
// We cannot disambiguate multi-segment paths right now as that requires type
561+
// checking.
562+
if path.segments.len() == 1 && path.segments[0].args.is_none() {
563+
let mut check_ns = |ns| self.resolve_ident_in_lexical_scope(
564+
path.segments[0].ident, ns, None, path.span
565+
).is_some();
566+
567+
if !check_ns(TypeNS) && check_ns(ValueNS) {
568+
// This must be equivalent to `visit_anon_const`, but we cannot call it
569+
// directly due to visitor lifetimes so we have to copy-paste some code.
570+
self.with_constant_rib(|this| {
571+
this.smart_resolve_path(
572+
ty.id,
573+
qself.as_ref(),
574+
path,
575+
PathSource::Expr(None)
576+
);
577+
578+
if let Some(ref qself) = *qself {
579+
this.visit_ty(&qself.ty);
580+
}
581+
this.visit_path(path, ty.id);
582+
});
583+
584+
return;
585+
}
586+
}
587+
}
588+
589+
self.visit_ty(ty);
590+
}
591+
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
592+
GenericArg::Const(ct) => self.visit_anon_const(ct),
593+
}
594+
}
549595
}
550596

551597
impl<'a, 'b> LateResolutionVisitor<'a, '_> {

src/librustc_resolve/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,14 @@ impl<'a> Resolver<'a> {
17261726
}
17271727
}
17281728

1729+
if ns == TypeNS {
1730+
if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
1731+
let binding = (Res::PrimTy(*prim_ty), ty::Visibility::Public,
1732+
DUMMY_SP, ExpnId::root()).to_name_binding(self.arenas);
1733+
return Some(LexicalScopeBinding::Item(binding));
1734+
}
1735+
}
1736+
17291737
None
17301738
}
17311739

src/test/ui/const-generics/const-generic-array-wrapper.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
#![feature(const_generics)]
44
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
55

6-
struct Foo<T, const N: usize>([T; {N}]);
6+
struct Foo<T, const N: usize>([T; N]);
77

8-
impl<T, const N: usize> Foo<T, {N}> {
8+
impl<T, const N: usize> Foo<T, N> {
99
fn foo(&self) -> usize {
10-
{N}
10+
N
1111
}
1212
}
1313

src/test/ui/const-generics/fn-const-param-call.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ fn function() -> u32 {
99

1010
struct Wrapper<const F: fn() -> u32>;
1111

12-
impl<const F: fn() -> u32> Wrapper<{F}> {
12+
impl<const F: fn() -> u32> Wrapper<F> {
1313
fn call() -> u32 {
1414
F()
1515
}
1616
}
1717

1818
fn main() {
19-
assert_eq!(Wrapper::<{function}>::call(), 17);
19+
assert_eq!(Wrapper::<function>::call(), 17);
2020
}

src/test/ui/const-generics/fn-const-param-infer.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ fn generic_arg<T>(val: T) -> bool { true }
1111
fn generic<T>(val: usize) -> bool { val != 1 }
1212

1313
fn main() {
14-
let _: Option<Checked<{not_one}>> = None;
15-
let _: Checked<{not_one}> = Checked::<{not_one}>;
16-
let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types
14+
let _: Option<Checked<not_one>> = None;
15+
let _: Checked<not_one> = Checked::<not_one>;
16+
let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
1717

18-
let _ = Checked::<{generic_arg}>;
18+
let _ = Checked::<generic_arg>;
1919
let _ = Checked::<{generic_arg::<usize>}>;
2020
let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
2121

22-
let _ = Checked::<{generic}>; //~ type annotations needed
22+
let _ = Checked::<generic>; //~ type annotations needed
2323
let _ = Checked::<{generic::<u16>}>;
2424
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
2525
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types

src/test/ui/const-generics/fn-const-param-infer.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ LL | #![feature(const_generics, const_compare_raw_pointers)]
77
= note: `#[warn(incomplete_features)]` on by default
88

99
error[E0308]: mismatched types
10-
--> $DIR/fn-const-param-infer.rs:16:33
10+
--> $DIR/fn-const-param-infer.rs:16:31
1111
|
12-
LL | let _: Checked<{not_one}> = Checked::<{not_two}>;
13-
| ^^^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two`
12+
LL | let _: Checked<not_one> = Checked::<not_two>;
13+
| ^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two`
1414
|
1515
= note: expected type `Checked<not_one>`
1616
found type `Checked<not_two>`
@@ -25,10 +25,10 @@ LL | let _ = Checked::<{generic_arg::<u32>}>;
2525
found type `fn(u32) -> bool {generic_arg::<u32>}`
2626

2727
error[E0282]: type annotations needed
28-
--> $DIR/fn-const-param-infer.rs:22:24
28+
--> $DIR/fn-const-param-infer.rs:22:23
2929
|
30-
LL | let _ = Checked::<{generic}>;
31-
| ^^^^^^^ cannot infer type for `T`
30+
LL | let _ = Checked::<generic>;
31+
| ^^^^^^^ cannot infer type for `T`
3232

3333
error[E0308]: mismatched types
3434
--> $DIR/fn-const-param-infer.rs:25:40

src/test/ui/const-generics/impl-const-generic-struct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
struct S<const X: u32>;
77

8-
impl<const X: u32> S<{X}> {
8+
impl<const X: u32> S<X> {
99
fn x() -> u32 {
1010
X
1111
}

src/test/ui/const-generics/raw-ptr-const-param-deref.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const A: u32 = 3;
66

77
struct Const<const P: *const u32>;
88

9-
impl<const P: *const u32> Const<{P}> {
9+
impl<const P: *const u32> Const<P> {
1010
fn get() -> u32 {
1111
unsafe {
1212
*P

src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::fmt;
77

88
struct Array<T, const N: usize>([T; N]);
99

10-
impl<T: fmt::Debug, const N: usize> fmt::Debug for Array<T, {N}> {
10+
impl<T: fmt::Debug, const N: usize> fmt::Debug for Array<T, N> {
1111
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1212
f.debug_list().entries(self.0.iter()).finish()
1313
}

src/test/ui/privacy/privacy-ns1.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ pub mod foo2 {
3232
fn test_glob2() {
3333
use foo2::*;
3434

35-
let _x: Box<Bar>; //~ ERROR expected type, found function `Bar`
35+
let _x: Box<Bar>; //~ ERROR wrong number of const arguments: expected 0, found 1
36+
//~^ ERROR wrong number of type arguments: expected 1, found 0
3637
}
3738

3839
// neither public

src/test/ui/privacy/privacy-ns1.stderr

+17-27
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,8 @@ LL | use foo2::Bar;
2020
LL | use foo3::Bar;
2121
|
2222

23-
error[E0573]: expected type, found function `Bar`
24-
--> $DIR/privacy-ns1.rs:35:17
25-
|
26-
LL | pub struct Baz;
27-
| --------------- similarly named struct `Baz` defined here
28-
...
29-
LL | let _x: Box<Bar>;
30-
| ^^^
31-
|
32-
help: a struct with a similar name exists
33-
|
34-
LL | let _x: Box<Baz>;
35-
| ^^^
36-
help: possible better candidates are found in other modules, you can import them into scope
37-
|
38-
LL | use foo1::Bar;
39-
|
40-
LL | use foo2::Bar;
41-
|
42-
LL | use foo3::Bar;
43-
|
44-
4523
error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope
46-
--> $DIR/privacy-ns1.rs:50:5
24+
--> $DIR/privacy-ns1.rs:51:5
4725
|
4826
LL | pub struct Baz;
4927
| --------------- similarly named unit struct `Baz` defined here
@@ -65,7 +43,7 @@ LL | use foo3::Bar;
6543
|
6644

6745
error[E0412]: cannot find type `Bar` in this scope
68-
--> $DIR/privacy-ns1.rs:51:17
46+
--> $DIR/privacy-ns1.rs:52:17
6947
|
7048
LL | pub struct Baz;
7149
| --------------- similarly named struct `Baz` defined here
@@ -86,7 +64,19 @@ LL | use foo2::Bar;
8664
LL | use foo3::Bar;
8765
|
8866

89-
error: aborting due to 4 previous errors
67+
error[E0107]: wrong number of const arguments: expected 0, found 1
68+
--> $DIR/privacy-ns1.rs:35:17
69+
|
70+
LL | let _x: Box<Bar>;
71+
| ^^^ unexpected const argument
72+
73+
error[E0107]: wrong number of type arguments: expected 1, found 0
74+
--> $DIR/privacy-ns1.rs:35:13
75+
|
76+
LL | let _x: Box<Bar>;
77+
| ^^^^^^^^ expected 1 type argument
78+
79+
error: aborting due to 5 previous errors
9080

91-
Some errors have detailed explanations: E0412, E0423, E0425, E0573.
92-
For more information about an error, try `rustc --explain E0412`.
81+
Some errors have detailed explanations: E0107, E0412, E0423, E0425.
82+
For more information about an error, try `rustc --explain E0107`.

src/test/ui/privacy/privacy-ns2.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,16 @@ pub mod foo2 {
3838
fn test_single2() {
3939
use foo2::Bar;
4040

41-
let _x : Box<Bar>; //~ ERROR expected type, found function `Bar`
41+
let _x : Box<Bar>; //~ ERROR wrong number of const arguments: expected 0, found 1
42+
//~^ ERROR wrong number of type arguments: expected 1, found 0
4243
let _x : Bar(); //~ ERROR expected type, found function `Bar`
4344
}
4445

4546
fn test_list2() {
4647
use foo2::{Bar,Baz};
4748

48-
let _x: Box<Bar>; //~ ERROR expected type, found function `Bar`
49+
let _x: Box<Bar>; //~ ERROR wrong number of const arguments: expected 0, found 1
50+
//~^ ERROR wrong number of type arguments: expected 1, found 0
4951
}
5052

5153
// neither public

0 commit comments

Comments
 (0)