From 367487fe88dca78cffad5138673d5259f7f7ba6b Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 28 May 2020 21:42:22 +0200 Subject: Support raw_ref_op's raw reference operator --- crates/ra_hir_def/src/body/lower.rs | 19 ++- crates/ra_hir_def/src/expr.rs | 3 +- crates/ra_hir_def/src/type_ref.rs | 16 ++ crates/ra_hir_ty/src/infer/expr.rs | 37 +++-- crates/ra_hir_ty/src/lib.rs | 18 ++- crates/ra_hir_ty/src/tests/coercion.rs | 17 +- crates/ra_hir_ty/src/tests/simple.rs | 20 +++ crates/ra_parser/src/grammar/expressions.rs | 16 +- crates/ra_syntax/src/ast/generated/nodes.rs | 3 + .../test_data/parser/inline/ok/0082_ref_expr.rast | 172 +++++++++++++++------ .../test_data/parser/inline/ok/0082_ref_expr.rs | 6 + xtask/src/ast_src.rs | 4 +- 12 files changed, 259 insertions(+), 72 deletions(-) diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index e08d62dd6..905c0cf5d 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -28,7 +28,7 @@ use crate::{ }, item_scope::BuiltinShadowMode, path::{GenericArgs, Path}, - type_ref::{Mutability, TypeRef}, + type_ref::{Mutability, Rawness, TypeRef}, AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, }; @@ -378,8 +378,21 @@ impl ExprCollector<'_> { } ast::Expr::RefExpr(e) => { let expr = self.collect_expr_opt(e.expr()); - let mutability = Mutability::from_mutable(e.mut_token().is_some()); - self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) + let raw_tok = e.raw_token().is_some(); + let mutability = if raw_tok { + if e.mut_token().is_some() { + Mutability::Mut + } else if e.const_token().is_some() { + Mutability::Shared + } else { + unreachable!("parser only remaps to raw_token() if matching mutability token follows") + } + } else { + Mutability::from_mutable(e.mut_token().is_some()) + }; + let rawness = Rawness::from_raw(raw_tok); + + self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) } ast::Expr::PrefixExpr(e) => { let expr = self.collect_expr_opt(e.expr()); diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index a0cdad529..f25c6f958 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs @@ -19,7 +19,7 @@ use ra_syntax::ast::RangeOp; use crate::{ builtin_type::{BuiltinFloat, BuiltinInt}, path::{GenericArgs, Path}, - type_ref::{Mutability, TypeRef}, + type_ref::{Mutability, Rawness, TypeRef}, }; pub type ExprId = Idx; @@ -110,6 +110,7 @@ pub enum Expr { }, Ref { expr: ExprId, + rawness: Rawness, mutability: Mutability, }, Box { diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 5bdad9efd..86a77b704 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -35,6 +35,22 @@ impl Mutability { } } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Rawness { + RawPtr, + Ref, +} + +impl Rawness { + pub fn from_raw(is_raw: bool) -> Rawness { + if is_raw { + Rawness::RawPtr + } else { + Rawness::Ref + } + } +} + /// Compare ty::Ty #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeRef { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b28724f0e..54bab3476 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -17,8 +17,8 @@ use crate::{ autoderef, method_resolution, op, traits::InEnvironment, utils::{generics, variant_data, Generics}, - ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, - Ty, TypeCtor, Uncertain, + ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, + TraitRef, Ty, TypeCtor, Uncertain, }; use super::{ @@ -350,19 +350,28 @@ impl<'a> InferenceContext<'a> { // FIXME check the cast... cast_ty } - Expr::Ref { expr, mutability } => { - let expectation = - if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() { - if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { - // FIXME: throw type error - expected mut reference but found shared ref, - // which cannot be coerced - } - Expectation::rvalue_hint(Ty::clone(exp_inner)) - } else { - Expectation::none() - }; + Expr::Ref { expr, rawness, mutability } => { + let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = + &expected.ty.as_reference_or_ptr() + { + if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { + // FIXME: throw type error - expected mut reference but found shared ref, + // which cannot be coerced + } + if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { + // FIXME: throw type error - expected reference but found ptr, + // which cannot be coerced + } + Expectation::rvalue_hint(Ty::clone(exp_inner)) + } else { + Expectation::none() + }; let inner_ty = self.infer_expr_inner(*expr, &expectation); - Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) + let ty = match rawness { + Rawness::RawPtr => TypeCtor::RawPtr(*mutability), + Rawness::Ref => TypeCtor::Ref(*mutability), + }; + Ty::apply_one(ty, inner_ty) } Expr::Box { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 93cb45a64..9fa8d3bdc 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -49,8 +49,10 @@ use std::sync::Arc; use std::{iter, mem}; use hir_def::{ - expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, - HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, + expr::ExprId, + type_ref::{Mutability, Rawness}, + AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, + TypeParamId, }; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -709,6 +711,18 @@ impl Ty { } } + pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { + match self { + Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { + Some((parameters.as_single(), Rawness::Ref, *mutability)) + } + Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => { + Some((parameters.as_single(), Rawness::RawPtr, *mutability)) + } + _ => None, + } + } + pub fn strip_references(&self) -> &Ty { let mut t: &Ty = self; diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 2cc4f4bf9..6f777ed8c 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() { assert_snapshot!( infer(r#" fn test() { - let x: &[i32] = &[1]; + let x: &[isize] = &[1]; + let x: *const [isize] = &[1]; } "#), @r###" - 11..40 '{ ...[1]; }': () - 21..22 'x': &[i32] - 33..37 '&[1]': &[i32; _] - 34..37 '[1]': [i32; _] - 35..36 '1': i32 + 11..76 '{ ...[1]; }': () + 21..22 'x': &[isize] + 35..39 '&[1]': &[isize; _] + 36..39 '[1]': [isize; _] + 37..38 '1': isize + 49..50 'x': *const [isize] + 69..73 '&[1]': &[isize; _] + 70..73 '[1]': [isize; _] + 71..72 '1': isize "###); } diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index fd2208af2..f1db34160 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -384,6 +384,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { ); } +#[test] +fn infer_raw_ref() { + assert_snapshot!( + infer(r#" +fn test(a: i32) { + &raw mut a; + &raw const a; +} +"#), + @r###" + 9..10 'a': i32 + 17..54 '{ ...t a; }': () + 23..33 '&raw mut a': *mut i32 + 32..33 'a': i32 + 39..51 '&raw const a': *const i32 + 50..51 'a': i32 + "### + ); +} + #[test] fn infer_literals() { assert_snapshot!( diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 34f039768..d6e8df32a 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs @@ -325,13 +325,27 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> let kind = match p.current() { // test ref_expr // fn foo() { + // // reference operator // let _ = &1; // let _ = &mut &f(); + // let _ = &raw; + // let _ = &raw.0; + // // raw reference operator + // let _ = &raw mut foo; + // let _ = &raw const foo; // } T![&] => { m = p.start(); p.bump(T![&]); - p.eat(T![mut]); + if p.at(IDENT) + && p.at_contextual_kw("raw") + && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) + { + p.bump_remap(T![raw]); + p.bump_any(); + } else { + p.eat(T![mut]); + } REF_EXPR } // test unary_expr diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index cf6067e57..255402fbc 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs @@ -1235,6 +1235,8 @@ impl CastExpr { /// ``` /// ❰ &foo ❱; /// ❰ &mut bar ❱; +/// ❰ &raw const bar ❱; +/// ❰ &raw mut bar ❱; /// ``` /// /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators) @@ -1247,6 +1249,7 @@ impl RefExpr { pub fn amp_token(&self) -> Option { support::token(&self.syntax, T![&]) } pub fn raw_token(&self) -> Option { support::token(&self.syntax, T![raw]) } pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } pub fn expr(&self) -> Option { support::child(&self.syntax) } } /// Prefix operator call. This is either `!` or `*` or `-`. diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast index 7fe96e17d..58bdf7e34 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast @@ -1,5 +1,5 @@ -SOURCE_FILE@0..52 - FN_DEF@0..51 +SOURCE_FILE@0..200 + FN_DEF@0..199 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -8,47 +8,131 @@ SOURCE_FILE@0..52 L_PAREN@6..7 "(" R_PAREN@7..8 ")" WHITESPACE@8..9 " " - BLOCK_EXPR@9..51 + BLOCK_EXPR@9..199 L_CURLY@9..10 "{" WHITESPACE@10..15 "\n " - LET_STMT@15..26 - LET_KW@15..18 "let" - WHITESPACE@18..19 " " - PLACEHOLDER_PAT@19..20 - UNDERSCORE@19..20 "_" - WHITESPACE@20..21 " " - EQ@21..22 "=" - WHITESPACE@22..23 " " - REF_EXPR@23..25 - AMP@23..24 "&" - LITERAL@24..25 - INT_NUMBER@24..25 "1" - SEMICOLON@25..26 ";" - WHITESPACE@26..31 "\n " - LET_STMT@31..49 - LET_KW@31..34 "let" - WHITESPACE@34..35 " " - PLACEHOLDER_PAT@35..36 - UNDERSCORE@35..36 "_" - WHITESPACE@36..37 " " - EQ@37..38 "=" - WHITESPACE@38..39 " " - REF_EXPR@39..48 - AMP@39..40 "&" - MUT_KW@40..43 "mut" - WHITESPACE@43..44 " " - REF_EXPR@44..48 - AMP@44..45 "&" - CALL_EXPR@45..48 - PATH_EXPR@45..46 - PATH@45..46 - PATH_SEGMENT@45..46 - NAME_REF@45..46 - IDENT@45..46 "f" - ARG_LIST@46..48 - L_PAREN@46..47 "(" - R_PAREN@47..48 ")" - SEMICOLON@48..49 ";" - WHITESPACE@49..50 "\n" - R_CURLY@50..51 "}" - WHITESPACE@51..52 "\n" + COMMENT@15..36 "// reference operator" + WHITESPACE@36..41 "\n " + LET_STMT@41..52 + LET_KW@41..44 "let" + WHITESPACE@44..45 " " + PLACEHOLDER_PAT@45..46 + UNDERSCORE@45..46 "_" + WHITESPACE@46..47 " " + EQ@47..48 "=" + WHITESPACE@48..49 " " + REF_EXPR@49..51 + AMP@49..50 "&" + LITERAL@50..51 + INT_NUMBER@50..51 "1" + SEMICOLON@51..52 ";" + WHITESPACE@52..57 "\n " + LET_STMT@57..75 + LET_KW@57..60 "let" + WHITESPACE@60..61 " " + PLACEHOLDER_PAT@61..62 + UNDERSCORE@61..62 "_" + WHITESPACE@62..63 " " + EQ@63..64 "=" + WHITESPACE@64..65 " " + REF_EXPR@65..74 + AMP@65..66 "&" + MUT_KW@66..69 "mut" + WHITESPACE@69..70 " " + REF_EXPR@70..74 + AMP@70..71 "&" + CALL_EXPR@71..74 + PATH_EXPR@71..72 + PATH@71..72 + PATH_SEGMENT@71..72 + NAME_REF@71..72 + IDENT@71..72 "f" + ARG_LIST@72..74 + L_PAREN@72..73 "(" + R_PAREN@73..74 ")" + SEMICOLON@74..75 ";" + WHITESPACE@75..80 "\n " + LET_STMT@80..93 + LET_KW@80..83 "let" + WHITESPACE@83..84 " " + PLACEHOLDER_PAT@84..85 + UNDERSCORE@84..85 "_" + WHITESPACE@85..86 " " + EQ@86..87 "=" + WHITESPACE@87..88 " " + REF_EXPR@88..92 + AMP@88..89 "&" + PATH_EXPR@89..92 + PATH@89..92 + PATH_SEGMENT@89..92 + NAME_REF@89..92 + IDENT@89..92 "raw" + SEMICOLON@92..93 ";" + WHITESPACE@93..98 "\n " + LET_STMT@98..113 + LET_KW@98..101 "let" + WHITESPACE@101..102 " " + PLACEHOLDER_PAT@102..103 + UNDERSCORE@102..103 "_" + WHITESPACE@103..104 " " + EQ@104..105 "=" + WHITESPACE@105..106 " " + REF_EXPR@106..112 + AMP@106..107 "&" + FIELD_EXPR@107..112 + PATH_EXPR@107..110 + PATH@107..110 + PATH_SEGMENT@107..110 + NAME_REF@107..110 + IDENT@107..110 "raw" + DOT@110..111 "." + NAME_REF@111..112 + INT_NUMBER@111..112 "0" + SEMICOLON@112..113 ";" + WHITESPACE@113..118 "\n " + COMMENT@118..143 "// raw reference oper ..." + WHITESPACE@143..148 "\n " + LET_STMT@148..169 + LET_KW@148..151 "let" + WHITESPACE@151..152 " " + PLACEHOLDER_PAT@152..153 + UNDERSCORE@152..153 "_" + WHITESPACE@153..154 " " + EQ@154..155 "=" + WHITESPACE@155..156 " " + REF_EXPR@156..168 + AMP@156..157 "&" + RAW_KW@157..160 "raw" + WHITESPACE@160..161 " " + MUT_KW@161..164 "mut" + WHITESPACE@164..165 " " + PATH_EXPR@165..168 + PATH@165..168 + PATH_SEGMENT@165..168 + NAME_REF@165..168 + IDENT@165..168 "foo" + SEMICOLON@168..169 ";" + WHITESPACE@169..174 "\n " + LET_STMT@174..197 + LET_KW@174..177 "let" + WHITESPACE@177..178 " " + PLACEHOLDER_PAT@178..179 + UNDERSCORE@178..179 "_" + WHITESPACE@179..180 " " + EQ@180..181 "=" + WHITESPACE@181..182 " " + REF_EXPR@182..196 + AMP@182..183 "&" + RAW_KW@183..186 "raw" + WHITESPACE@186..187 " " + CONST_KW@187..192 "const" + WHITESPACE@192..193 " " + PATH_EXPR@193..196 + PATH@193..196 + PATH_SEGMENT@193..196 + NAME_REF@193..196 + IDENT@193..196 "foo" + SEMICOLON@196..197 ";" + WHITESPACE@197..198 "\n" + R_CURLY@198..199 "}" + WHITESPACE@199..200 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rs index 2dac6be95..c5262f446 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rs @@ -1,4 +1,10 @@ fn foo() { + // reference operator let _ = &1; let _ = &mut &f(); + let _ = &raw; + let _ = &raw.0; + // raw reference operator + let _ = &raw mut foo; + let _ = &raw const foo; } diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 394a7bc88..d4621930e 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -1153,10 +1153,12 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { /// ``` /// ❰ &foo ❱; /// ❰ &mut bar ❱; + /// ❰ &raw const bar ❱; + /// ❰ &raw mut bar ❱; /// ``` /// /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators) - struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr } + struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr } /// Prefix operator call. This is either `!` or `*` or `-`. /// -- cgit v1.2.3