Support raw_ref_op's raw reference operator

This commit is contained in:
robojumper 2020-05-28 21:42:22 +02:00
parent 190a0595a4
commit 367487fe88
12 changed files with 259 additions and 72 deletions

View file

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

View file

@ -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<Expr>;
@ -110,6 +110,7 @@ pub enum Expr {
},
Ref {
expr: ExprId,
rawness: Rawness,
mutability: Mutability,
},
Box {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<SyntaxToken> { support::token(&self.syntax, T![&]) }
pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
}
/// Prefix operator call. This is either `!` or `*` or `-`.

View file

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

View file

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

View file

@ -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 `-`.
///