Skip to content

Commit 6f38552

Browse files
committed
Add validation check for ambiguous trait objects
1 parent 87cb840 commit 6f38552

File tree

5 files changed

+448
-1
lines changed

5 files changed

+448
-1
lines changed

crates/syntax/src/validation.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
mod block;
44

55
use crate::{
6-
ast, match_ast, AstNode, SyntaxError,
6+
algo, ast, match_ast, AstNode, SyntaxError,
77
SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS},
88
SyntaxNode, SyntaxToken, TextSize, T,
99
};
10+
use rowan::Direction;
1011
use rustc_lexer::unescape::{
1112
self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode,
1213
};
@@ -95,6 +96,9 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
9596
ast::Visibility(it) => validate_visibility(it, &mut errors),
9697
ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
9798
ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
99+
ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
100+
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
101+
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
98102
_ => (),
99103
}
100104
}
@@ -301,3 +305,42 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro
301305
return true;
302306
}
303307
}
308+
309+
fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) {
310+
if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
311+
if let Some(err) = validate_trait_object_ty(ty) {
312+
errors.push(err);
313+
}
314+
}
315+
}
316+
317+
fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) {
318+
if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
319+
if let Some(err) = validate_trait_object_ty(ty) {
320+
errors.push(err);
321+
}
322+
}
323+
}
324+
325+
fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) {
326+
if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) {
327+
if let Some(err) = validate_trait_object_ty(ty) {
328+
errors.push(err);
329+
}
330+
}
331+
}
332+
333+
fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
334+
let tbl = ty.type_bound_list()?;
335+
336+
if tbl.bounds().count() > 1 {
337+
let dyn_token = ty.dyn_token()?;
338+
let potential_parentheses =
339+
algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
340+
let kind = potential_parentheses.kind();
341+
if !matches!(kind, T!['('] | T![<] | T![=]) {
342+
return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
343+
}
344+
}
345+
None
346+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
SOURCE_FILE@0..187
2+
TYPE_ALIAS@0..35
3+
TYPE_KW@0..4 "type"
4+
WHITESPACE@4..5 " "
5+
NAME@5..8
6+
IDENT@5..8 "Foo"
7+
GENERIC_PARAM_LIST@8..12
8+
L_ANGLE@8..9 "<"
9+
LIFETIME_PARAM@9..11
10+
LIFETIME@9..11 "\'a"
11+
R_ANGLE@11..12 ">"
12+
WHITESPACE@12..13 " "
13+
EQ@13..14 "="
14+
WHITESPACE@14..15 " "
15+
REF_TYPE@15..34
16+
AMP@15..16 "&"
17+
LIFETIME@16..18 "\'a"
18+
WHITESPACE@18..19 " "
19+
DYN_TRAIT_TYPE@19..34
20+
DYN_KW@19..22 "dyn"
21+
WHITESPACE@22..23 " "
22+
TYPE_BOUND_LIST@23..34
23+
TYPE_BOUND@23..27
24+
PATH_TYPE@23..27
25+
PATH@23..27
26+
PATH_SEGMENT@23..27
27+
NAME_REF@23..27
28+
IDENT@23..27 "Send"
29+
WHITESPACE@27..28 " "
30+
PLUS@28..29 "+"
31+
WHITESPACE@29..30 " "
32+
TYPE_BOUND@30..34
33+
PATH_TYPE@30..34
34+
PATH@30..34
35+
PATH_SEGMENT@30..34
36+
NAME_REF@30..34
37+
IDENT@30..34 "Sync"
38+
SEMICOLON@34..35 ";"
39+
WHITESPACE@35..36 "\n"
40+
TYPE_ALIAS@36..70
41+
TYPE_KW@36..40 "type"
42+
WHITESPACE@40..41 " "
43+
NAME@41..44
44+
IDENT@41..44 "Foo"
45+
WHITESPACE@44..45 " "
46+
EQ@45..46 "="
47+
WHITESPACE@46..47 " "
48+
PTR_TYPE@47..69
49+
STAR@47..48 "*"
50+
CONST_KW@48..53 "const"
51+
WHITESPACE@53..54 " "
52+
DYN_TRAIT_TYPE@54..69
53+
DYN_KW@54..57 "dyn"
54+
WHITESPACE@57..58 " "
55+
TYPE_BOUND_LIST@58..69
56+
TYPE_BOUND@58..62
57+
PATH_TYPE@58..62
58+
PATH@58..62
59+
PATH_SEGMENT@58..62
60+
NAME_REF@58..62
61+
IDENT@58..62 "Send"
62+
WHITESPACE@62..63 " "
63+
PLUS@63..64 "+"
64+
WHITESPACE@64..65 " "
65+
TYPE_BOUND@65..69
66+
PATH_TYPE@65..69
67+
PATH@65..69
68+
PATH_SEGMENT@65..69
69+
NAME_REF@65..69
70+
IDENT@65..69 "Sync"
71+
SEMICOLON@69..70 ";"
72+
WHITESPACE@70..71 "\n"
73+
TYPE_ALIAS@71..109
74+
TYPE_KW@71..75 "type"
75+
WHITESPACE@75..76 " "
76+
NAME@76..79
77+
IDENT@76..79 "Foo"
78+
WHITESPACE@79..80 " "
79+
EQ@80..81 "="
80+
WHITESPACE@81..82 " "
81+
FN_PTR_TYPE@82..108
82+
FN_KW@82..84 "fn"
83+
PARAM_LIST@84..86
84+
L_PAREN@84..85 "("
85+
R_PAREN@85..86 ")"
86+
WHITESPACE@86..87 " "
87+
RET_TYPE@87..108
88+
THIN_ARROW@87..89 "->"
89+
WHITESPACE@89..90 " "
90+
DYN_TRAIT_TYPE@90..108
91+
DYN_KW@90..93 "dyn"
92+
WHITESPACE@93..94 " "
93+
TYPE_BOUND_LIST@94..108
94+
TYPE_BOUND@94..98
95+
PATH_TYPE@94..98
96+
PATH@94..98
97+
PATH_SEGMENT@94..98
98+
NAME_REF@94..98
99+
IDENT@94..98 "Send"
100+
WHITESPACE@98..99 " "
101+
PLUS@99..100 "+"
102+
WHITESPACE@100..101 " "
103+
TYPE_BOUND@101..108
104+
LIFETIME@101..108 "\'static"
105+
SEMICOLON@108..109 ";"
106+
WHITESPACE@109..110 "\n"
107+
FN@110..186
108+
FN_KW@110..112 "fn"
109+
WHITESPACE@112..113 " "
110+
NAME@113..117
111+
IDENT@113..117 "main"
112+
PARAM_LIST@117..119
113+
L_PAREN@117..118 "("
114+
R_PAREN@118..119 ")"
115+
WHITESPACE@119..120 " "
116+
BLOCK_EXPR@120..186
117+
L_CURLY@120..121 "{"
118+
WHITESPACE@121..126 "\n "
119+
LET_STMT@126..184
120+
LET_KW@126..129 "let"
121+
WHITESPACE@129..130 " "
122+
IDENT_PAT@130..131
123+
NAME@130..131
124+
IDENT@130..131 "b"
125+
WHITESPACE@131..132 " "
126+
EQ@132..133 "="
127+
WHITESPACE@133..134 " "
128+
CAST_EXPR@134..183
129+
PAREN_EXPR@134..138
130+
L_PAREN@134..135 "("
131+
REF_EXPR@135..137
132+
AMP@135..136 "&"
133+
PATH_EXPR@136..137
134+
PATH@136..137
135+
PATH_SEGMENT@136..137
136+
NAME_REF@136..137
137+
IDENT@136..137 "a"
138+
R_PAREN@137..138 ")"
139+
WHITESPACE@138..139 " "
140+
AS_KW@139..141 "as"
141+
WHITESPACE@141..142 " "
142+
REF_TYPE@142..183
143+
AMP@142..143 "&"
144+
DYN_TRAIT_TYPE@143..183
145+
DYN_KW@143..146 "dyn"
146+
WHITESPACE@146..147 " "
147+
TYPE_BOUND_LIST@147..183
148+
TYPE_BOUND@147..175
149+
PATH_TYPE@147..175
150+
PATH@147..175
151+
PATH_SEGMENT@147..175
152+
NAME_REF@147..150
153+
IDENT@147..150 "Add"
154+
GENERIC_ARG_LIST@150..175
155+
L_ANGLE@150..151 "<"
156+
TYPE_ARG@151..156
157+
PATH_TYPE@151..156
158+
PATH@151..156
159+
PATH_SEGMENT@151..156
160+
NAME_REF@151..156
161+
IDENT@151..156 "Other"
162+
COMMA@156..157 ","
163+
WHITESPACE@157..158 " "
164+
ASSOC_TYPE_ARG@158..174
165+
NAME_REF@158..164
166+
IDENT@158..164 "Output"
167+
WHITESPACE@164..165 " "
168+
EQ@165..166 "="
169+
WHITESPACE@166..167 " "
170+
PATH_TYPE@167..174
171+
PATH@167..174
172+
PATH_SEGMENT@167..174
173+
NAME_REF@167..174
174+
IDENT@167..174 "Addable"
175+
R_ANGLE@174..175 ">"
176+
WHITESPACE@175..176 " "
177+
PLUS@176..177 "+"
178+
WHITESPACE@177..178 " "
179+
TYPE_BOUND@178..183
180+
PATH_TYPE@178..183
181+
PATH@178..183
182+
PATH_SEGMENT@178..183
183+
NAME_REF@178..183
184+
IDENT@178..183 "Other"
185+
SEMICOLON@183..184 ";"
186+
WHITESPACE@184..185 "\n"
187+
R_CURLY@185..186 "}"
188+
WHITESPACE@186..187 "\n"
189+
error 19..34: ambiguous `+` in a type
190+
error 54..69: ambiguous `+` in a type
191+
error 90..108: ambiguous `+` in a type
192+
error 143..183: ambiguous `+` in a type
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type Foo<'a> = &'a dyn Send + Sync;
2+
type Foo = *const dyn Send + Sync;
3+
type Foo = fn() -> dyn Send + 'static;
4+
fn main() {
5+
let b = (&a) as &dyn Add<Other, Output = Addable> + Other;
6+
}

0 commit comments

Comments
 (0)