From 6f38552edb7be10d526aa6510200b547a301593f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 6 Oct 2020 23:46:26 +0200 Subject: Add validation check for ambiguous trait objects --- crates/syntax/src/validation.rs | 45 ++++- .../parser/err/0046_ambiguous_trait_object.rast | 192 ++++++++++++++++++++ .../parser/err/0046_ambiguous_trait_object.rs | 6 + .../parser/ok/0069_multi_trait_object.rast | 200 +++++++++++++++++++++ .../test_data/parser/ok/0069_multi_trait_object.rs | 6 + 5 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast create mode 100644 crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs create mode 100644 crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast create mode 100644 crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs (limited to 'crates') diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 2dddaf09a..0f9a5e8ae 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs @@ -3,10 +3,11 @@ mod block; use crate::{ - ast, match_ast, AstNode, SyntaxError, + algo, ast, match_ast, AstNode, SyntaxError, SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS}, SyntaxNode, SyntaxToken, TextSize, T, }; +use rowan::Direction; use rustc_lexer::unescape::{ self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, }; @@ -95,6 +96,9 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec { ast::Visibility(it) => validate_visibility(it, &mut errors), ast::RangeExpr(it) => validate_range_expr(it, &mut errors), ast::PathSegment(it) => validate_path_keywords(it, &mut errors), + ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors), + ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors), + ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors), _ => (), } } @@ -301,3 +305,42 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec) { + if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { + if let Some(err) = validate_trait_object_ty(ty) { + errors.push(err); + } + } +} + +fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec) { + if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { + if let Some(err) = validate_trait_object_ty(ty) { + errors.push(err); + } + } +} + +fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec) { + if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) { + if let Some(err) = validate_trait_object_ty(ty) { + errors.push(err); + } + } +} + +fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option { + let tbl = ty.type_bound_list()?; + + if tbl.bounds().count() > 1 { + let dyn_token = ty.dyn_token()?; + let potential_parentheses = + algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; + let kind = potential_parentheses.kind(); + if !matches!(kind, T!['('] | T![<] | T![=]) { + return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); + } + } + None +} diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast new file mode 100644 index 000000000..592741cdb --- /dev/null +++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast @@ -0,0 +1,192 @@ +SOURCE_FILE@0..187 + TYPE_ALIAS@0..35 + TYPE_KW@0..4 "type" + WHITESPACE@4..5 " " + NAME@5..8 + IDENT@5..8 "Foo" + GENERIC_PARAM_LIST@8..12 + L_ANGLE@8..9 "<" + LIFETIME_PARAM@9..11 + LIFETIME@9..11 "\'a" + R_ANGLE@11..12 ">" + WHITESPACE@12..13 " " + EQ@13..14 "=" + WHITESPACE@14..15 " " + REF_TYPE@15..34 + AMP@15..16 "&" + LIFETIME@16..18 "\'a" + WHITESPACE@18..19 " " + DYN_TRAIT_TYPE@19..34 + DYN_KW@19..22 "dyn" + WHITESPACE@22..23 " " + TYPE_BOUND_LIST@23..34 + TYPE_BOUND@23..27 + PATH_TYPE@23..27 + PATH@23..27 + PATH_SEGMENT@23..27 + NAME_REF@23..27 + IDENT@23..27 "Send" + WHITESPACE@27..28 " " + PLUS@28..29 "+" + WHITESPACE@29..30 " " + TYPE_BOUND@30..34 + PATH_TYPE@30..34 + PATH@30..34 + PATH_SEGMENT@30..34 + NAME_REF@30..34 + IDENT@30..34 "Sync" + SEMICOLON@34..35 ";" + WHITESPACE@35..36 "\n" + TYPE_ALIAS@36..70 + TYPE_KW@36..40 "type" + WHITESPACE@40..41 " " + NAME@41..44 + IDENT@41..44 "Foo" + WHITESPACE@44..45 " " + EQ@45..46 "=" + WHITESPACE@46..47 " " + PTR_TYPE@47..69 + STAR@47..48 "*" + CONST_KW@48..53 "const" + WHITESPACE@53..54 " " + DYN_TRAIT_TYPE@54..69 + DYN_KW@54..57 "dyn" + WHITESPACE@57..58 " " + TYPE_BOUND_LIST@58..69 + TYPE_BOUND@58..62 + PATH_TYPE@58..62 + PATH@58..62 + PATH_SEGMENT@58..62 + NAME_REF@58..62 + IDENT@58..62 "Send" + WHITESPACE@62..63 " " + PLUS@63..64 "+" + WHITESPACE@64..65 " " + TYPE_BOUND@65..69 + PATH_TYPE@65..69 + PATH@65..69 + PATH_SEGMENT@65..69 + NAME_REF@65..69 + IDENT@65..69 "Sync" + SEMICOLON@69..70 ";" + WHITESPACE@70..71 "\n" + TYPE_ALIAS@71..109 + TYPE_KW@71..75 "type" + WHITESPACE@75..76 " " + NAME@76..79 + IDENT@76..79 "Foo" + WHITESPACE@79..80 " " + EQ@80..81 "=" + WHITESPACE@81..82 " " + FN_PTR_TYPE@82..108 + FN_KW@82..84 "fn" + PARAM_LIST@84..86 + L_PAREN@84..85 "(" + R_PAREN@85..86 ")" + WHITESPACE@86..87 " " + RET_TYPE@87..108 + THIN_ARROW@87..89 "->" + WHITESPACE@89..90 " " + DYN_TRAIT_TYPE@90..108 + DYN_KW@90..93 "dyn" + WHITESPACE@93..94 " " + TYPE_BOUND_LIST@94..108 + TYPE_BOUND@94..98 + PATH_TYPE@94..98 + PATH@94..98 + PATH_SEGMENT@94..98 + NAME_REF@94..98 + IDENT@94..98 "Send" + WHITESPACE@98..99 " " + PLUS@99..100 "+" + WHITESPACE@100..101 " " + TYPE_BOUND@101..108 + LIFETIME@101..108 "\'static" + SEMICOLON@108..109 ";" + WHITESPACE@109..110 "\n" + FN@110..186 + FN_KW@110..112 "fn" + WHITESPACE@112..113 " " + NAME@113..117 + IDENT@113..117 "main" + PARAM_LIST@117..119 + L_PAREN@117..118 "(" + R_PAREN@118..119 ")" + WHITESPACE@119..120 " " + BLOCK_EXPR@120..186 + L_CURLY@120..121 "{" + WHITESPACE@121..126 "\n " + LET_STMT@126..184 + LET_KW@126..129 "let" + WHITESPACE@129..130 " " + IDENT_PAT@130..131 + NAME@130..131 + IDENT@130..131 "b" + WHITESPACE@131..132 " " + EQ@132..133 "=" + WHITESPACE@133..134 " " + CAST_EXPR@134..183 + PAREN_EXPR@134..138 + L_PAREN@134..135 "(" + REF_EXPR@135..137 + AMP@135..136 "&" + PATH_EXPR@136..137 + PATH@136..137 + PATH_SEGMENT@136..137 + NAME_REF@136..137 + IDENT@136..137 "a" + R_PAREN@137..138 ")" + WHITESPACE@138..139 " " + AS_KW@139..141 "as" + WHITESPACE@141..142 " " + REF_TYPE@142..183 + AMP@142..143 "&" + DYN_TRAIT_TYPE@143..183 + DYN_KW@143..146 "dyn" + WHITESPACE@146..147 " " + TYPE_BOUND_LIST@147..183 + TYPE_BOUND@147..175 + PATH_TYPE@147..175 + PATH@147..175 + PATH_SEGMENT@147..175 + NAME_REF@147..150 + IDENT@147..150 "Add" + GENERIC_ARG_LIST@150..175 + L_ANGLE@150..151 "<" + TYPE_ARG@151..156 + PATH_TYPE@151..156 + PATH@151..156 + PATH_SEGMENT@151..156 + NAME_REF@151..156 + IDENT@151..156 "Other" + COMMA@156..157 "," + WHITESPACE@157..158 " " + ASSOC_TYPE_ARG@158..174 + NAME_REF@158..164 + IDENT@158..164 "Output" + WHITESPACE@164..165 " " + EQ@165..166 "=" + WHITESPACE@166..167 " " + PATH_TYPE@167..174 + PATH@167..174 + PATH_SEGMENT@167..174 + NAME_REF@167..174 + IDENT@167..174 "Addable" + R_ANGLE@174..175 ">" + WHITESPACE@175..176 " " + PLUS@176..177 "+" + WHITESPACE@177..178 " " + TYPE_BOUND@178..183 + PATH_TYPE@178..183 + PATH@178..183 + PATH_SEGMENT@178..183 + NAME_REF@178..183 + IDENT@178..183 "Other" + SEMICOLON@183..184 ";" + WHITESPACE@184..185 "\n" + R_CURLY@185..186 "}" + WHITESPACE@186..187 "\n" +error 19..34: ambiguous `+` in a type +error 54..69: ambiguous `+` in a type +error 90..108: ambiguous `+` in a type +error 143..183: ambiguous `+` in a type diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs new file mode 100644 index 000000000..3a73d81bb --- /dev/null +++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs @@ -0,0 +1,6 @@ +type Foo<'a> = &'a dyn Send + Sync; +type Foo = *const dyn Send + Sync; +type Foo = fn() -> dyn Send + 'static; +fn main() { + let b = (&a) as &dyn Add + Other; +} diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast new file mode 100644 index 000000000..0cd868a83 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast @@ -0,0 +1,200 @@ +SOURCE_FILE@0..195 + TYPE_ALIAS@0..37 + TYPE_KW@0..4 "type" + WHITESPACE@4..5 " " + NAME@5..8 + IDENT@5..8 "Foo" + GENERIC_PARAM_LIST@8..12 + L_ANGLE@8..9 "<" + LIFETIME_PARAM@9..11 + LIFETIME@9..11 "\'a" + R_ANGLE@11..12 ">" + WHITESPACE@12..13 " " + EQ@13..14 "=" + WHITESPACE@14..15 " " + REF_TYPE@15..36 + AMP@15..16 "&" + LIFETIME@16..18 "\'a" + WHITESPACE@18..19 " " + PAREN_TYPE@19..36 + L_PAREN@19..20 "(" + DYN_TRAIT_TYPE@20..35 + DYN_KW@20..23 "dyn" + WHITESPACE@23..24 " " + TYPE_BOUND_LIST@24..35 + TYPE_BOUND@24..28 + PATH_TYPE@24..28 + PATH@24..28 + PATH_SEGMENT@24..28 + NAME_REF@24..28 + IDENT@24..28 "Send" + WHITESPACE@28..29 " " + PLUS@29..30 "+" + WHITESPACE@30..31 " " + TYPE_BOUND@31..35 + PATH_TYPE@31..35 + PATH@31..35 + PATH_SEGMENT@31..35 + NAME_REF@31..35 + IDENT@31..35 "Sync" + R_PAREN@35..36 ")" + SEMICOLON@36..37 ";" + WHITESPACE@37..38 "\n" + TYPE_ALIAS@38..74 + TYPE_KW@38..42 "type" + WHITESPACE@42..43 " " + NAME@43..46 + IDENT@43..46 "Foo" + WHITESPACE@46..47 " " + EQ@47..48 "=" + WHITESPACE@48..49 " " + PTR_TYPE@49..73 + STAR@49..50 "*" + CONST_KW@50..55 "const" + WHITESPACE@55..56 " " + PAREN_TYPE@56..73 + L_PAREN@56..57 "(" + DYN_TRAIT_TYPE@57..72 + DYN_KW@57..60 "dyn" + WHITESPACE@60..61 " " + TYPE_BOUND_LIST@61..72 + TYPE_BOUND@61..65 + PATH_TYPE@61..65 + PATH@61..65 + PATH_SEGMENT@61..65 + NAME_REF@61..65 + IDENT@61..65 "Send" + WHITESPACE@65..66 " " + PLUS@66..67 "+" + WHITESPACE@67..68 " " + TYPE_BOUND@68..72 + PATH_TYPE@68..72 + PATH@68..72 + PATH_SEGMENT@68..72 + NAME_REF@68..72 + IDENT@68..72 "Sync" + R_PAREN@72..73 ")" + SEMICOLON@73..74 ";" + WHITESPACE@74..75 "\n" + TYPE_ALIAS@75..115 + TYPE_KW@75..79 "type" + WHITESPACE@79..80 " " + NAME@80..83 + IDENT@80..83 "Foo" + WHITESPACE@83..84 " " + EQ@84..85 "=" + WHITESPACE@85..86 " " + FN_PTR_TYPE@86..114 + FN_KW@86..88 "fn" + PARAM_LIST@88..90 + L_PAREN@88..89 "(" + R_PAREN@89..90 ")" + WHITESPACE@90..91 " " + RET_TYPE@91..114 + THIN_ARROW@91..93 "->" + WHITESPACE@93..94 " " + PAREN_TYPE@94..114 + L_PAREN@94..95 "(" + DYN_TRAIT_TYPE@95..113 + DYN_KW@95..98 "dyn" + WHITESPACE@98..99 " " + TYPE_BOUND_LIST@99..113 + TYPE_BOUND@99..103 + PATH_TYPE@99..103 + PATH@99..103 + PATH_SEGMENT@99..103 + NAME_REF@99..103 + IDENT@99..103 "Send" + WHITESPACE@103..104 " " + PLUS@104..105 "+" + WHITESPACE@105..106 " " + TYPE_BOUND@106..113 + LIFETIME@106..113 "\'static" + R_PAREN@113..114 ")" + SEMICOLON@114..115 ";" + WHITESPACE@115..116 "\n" + FN@116..194 + FN_KW@116..118 "fn" + WHITESPACE@118..119 " " + NAME@119..123 + IDENT@119..123 "main" + PARAM_LIST@123..125 + L_PAREN@123..124 "(" + R_PAREN@124..125 ")" + WHITESPACE@125..126 " " + BLOCK_EXPR@126..194 + L_CURLY@126..127 "{" + WHITESPACE@127..132 "\n " + LET_STMT@132..192 + LET_KW@132..135 "let" + WHITESPACE@135..136 " " + IDENT_PAT@136..137 + NAME@136..137 + IDENT@136..137 "b" + WHITESPACE@137..138 " " + EQ@138..139 "=" + WHITESPACE@139..140 " " + CAST_EXPR@140..191 + PAREN_EXPR@140..144 + L_PAREN@140..141 "(" + REF_EXPR@141..143 + AMP@141..142 "&" + PATH_EXPR@142..143 + PATH@142..143 + PATH_SEGMENT@142..143 + NAME_REF@142..143 + IDENT@142..143 "a" + R_PAREN@143..144 ")" + WHITESPACE@144..145 " " + AS_KW@145..147 "as" + WHITESPACE@147..148 " " + REF_TYPE@148..191 + AMP@148..149 "&" + PAREN_TYPE@149..191 + L_PAREN@149..150 "(" + DYN_TRAIT_TYPE@150..190 + DYN_KW@150..153 "dyn" + WHITESPACE@153..154 " " + TYPE_BOUND_LIST@154..190 + TYPE_BOUND@154..182 + PATH_TYPE@154..182 + PATH@154..182 + PATH_SEGMENT@154..182 + NAME_REF@154..157 + IDENT@154..157 "Add" + GENERIC_ARG_LIST@157..182 + L_ANGLE@157..158 "<" + TYPE_ARG@158..163 + PATH_TYPE@158..163 + PATH@158..163 + PATH_SEGMENT@158..163 + NAME_REF@158..163 + IDENT@158..163 "Other" + COMMA@163..164 "," + WHITESPACE@164..165 " " + ASSOC_TYPE_ARG@165..181 + NAME_REF@165..171 + IDENT@165..171 "Output" + WHITESPACE@171..172 " " + EQ@172..173 "=" + WHITESPACE@173..174 " " + PATH_TYPE@174..181 + PATH@174..181 + PATH_SEGMENT@174..181 + NAME_REF@174..181 + IDENT@174..181 "Addable" + R_ANGLE@181..182 ">" + WHITESPACE@182..183 " " + PLUS@183..184 "+" + WHITESPACE@184..185 " " + TYPE_BOUND@185..190 + PATH_TYPE@185..190 + PATH@185..190 + PATH_SEGMENT@185..190 + NAME_REF@185..190 + IDENT@185..190 "Other" + R_PAREN@190..191 ")" + SEMICOLON@191..192 ";" + WHITESPACE@192..193 "\n" + R_CURLY@193..194 "}" + WHITESPACE@194..195 "\n" diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs new file mode 100644 index 000000000..97eb79c48 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs @@ -0,0 +1,6 @@ +type Foo<'a> = &'a (dyn Send + Sync); +type Foo = *const (dyn Send + Sync); +type Foo = fn() -> (dyn Send + 'static); +fn main() { + let b = (&a) as &(dyn Add + Other); +} -- cgit v1.2.3