Skip to content

Commit 30658b2

Browse files
Merge #4648
4648: Support raw_ref_op's raw reference operator r=matklad a=robojumper Fixes #4642. This syntax (and its semantics) are implemented in rustc behind the `raw_ref_op` feature. It is not entirely clear whether this is the syntax that will become stable, but [it seems like](rust-lang/rust#72279) rust-analyzer must still support this unstable syntax to support future stable rust. Also fixes a random inference failure involving a direct coercion from `&[T, _]` to `*const [T]`. Co-authored-by: robojumper <robojumper@gmail.com>
2 parents 190a059 + 367487f commit 30658b2

File tree

12 files changed

+259
-72
lines changed

12 files changed

+259
-72
lines changed

crates/ra_hir_def/src/body/lower.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::{
2828
},
2929
item_scope::BuiltinShadowMode,
3030
path::{GenericArgs, Path},
31-
type_ref::{Mutability, TypeRef},
31+
type_ref::{Mutability, Rawness, TypeRef},
3232
AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
3333
StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
3434
};
@@ -378,8 +378,21 @@ impl ExprCollector<'_> {
378378
}
379379
ast::Expr::RefExpr(e) => {
380380
let expr = self.collect_expr_opt(e.expr());
381-
let mutability = Mutability::from_mutable(e.mut_token().is_some());
382-
self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
381+
let raw_tok = e.raw_token().is_some();
382+
let mutability = if raw_tok {
383+
if e.mut_token().is_some() {
384+
Mutability::Mut
385+
} else if e.const_token().is_some() {
386+
Mutability::Shared
387+
} else {
388+
unreachable!("parser only remaps to raw_token() if matching mutability token follows")
389+
}
390+
} else {
391+
Mutability::from_mutable(e.mut_token().is_some())
392+
};
393+
let rawness = Rawness::from_raw(raw_tok);
394+
395+
self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
383396
}
384397
ast::Expr::PrefixExpr(e) => {
385398
let expr = self.collect_expr_opt(e.expr());

crates/ra_hir_def/src/expr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ra_syntax::ast::RangeOp;
1919
use crate::{
2020
builtin_type::{BuiltinFloat, BuiltinInt},
2121
path::{GenericArgs, Path},
22-
type_ref::{Mutability, TypeRef},
22+
type_ref::{Mutability, Rawness, TypeRef},
2323
};
2424

2525
pub type ExprId = Idx<Expr>;
@@ -110,6 +110,7 @@ pub enum Expr {
110110
},
111111
Ref {
112112
expr: ExprId,
113+
rawness: Rawness,
113114
mutability: Mutability,
114115
},
115116
Box {

crates/ra_hir_def/src/type_ref.rs

+16
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ impl Mutability {
3535
}
3636
}
3737

38+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
39+
pub enum Rawness {
40+
RawPtr,
41+
Ref,
42+
}
43+
44+
impl Rawness {
45+
pub fn from_raw(is_raw: bool) -> Rawness {
46+
if is_raw {
47+
Rawness::RawPtr
48+
} else {
49+
Rawness::Ref
50+
}
51+
}
52+
}
53+
3854
/// Compare ty::Ty
3955
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
4056
pub enum TypeRef {

crates/ra_hir_ty/src/infer/expr.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use crate::{
1717
autoderef, method_resolution, op,
1818
traits::InEnvironment,
1919
utils::{generics, variant_data, Generics},
20-
ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef,
21-
Ty, TypeCtor, Uncertain,
20+
ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21+
TraitRef, Ty, TypeCtor, Uncertain,
2222
};
2323

2424
use super::{
@@ -350,19 +350,28 @@ impl<'a> InferenceContext<'a> {
350350
// FIXME check the cast...
351351
cast_ty
352352
}
353-
Expr::Ref { expr, mutability } => {
354-
let expectation =
355-
if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() {
356-
if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
357-
// FIXME: throw type error - expected mut reference but found shared ref,
358-
// which cannot be coerced
359-
}
360-
Expectation::rvalue_hint(Ty::clone(exp_inner))
361-
} else {
362-
Expectation::none()
363-
};
353+
Expr::Ref { expr, rawness, mutability } => {
354+
let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) =
355+
&expected.ty.as_reference_or_ptr()
356+
{
357+
if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
358+
// FIXME: throw type error - expected mut reference but found shared ref,
359+
// which cannot be coerced
360+
}
361+
if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
362+
// FIXME: throw type error - expected reference but found ptr,
363+
// which cannot be coerced
364+
}
365+
Expectation::rvalue_hint(Ty::clone(exp_inner))
366+
} else {
367+
Expectation::none()
368+
};
364369
let inner_ty = self.infer_expr_inner(*expr, &expectation);
365-
Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
370+
let ty = match rawness {
371+
Rawness::RawPtr => TypeCtor::RawPtr(*mutability),
372+
Rawness::Ref => TypeCtor::Ref(*mutability),
373+
};
374+
Ty::apply_one(ty, inner_ty)
366375
}
367376
Expr::Box { expr } => {
368377
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());

crates/ra_hir_ty/src/lib.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ use std::sync::Arc;
4949
use std::{iter, mem};
5050

5151
use hir_def::{
52-
expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId,
53-
HasModule, Lookup, TraitId, TypeAliasId, TypeParamId,
52+
expr::ExprId,
53+
type_ref::{Mutability, Rawness},
54+
AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
55+
TypeParamId,
5456
};
5557
use ra_db::{impl_intern_key, salsa, CrateId};
5658

@@ -709,6 +711,18 @@ impl Ty {
709711
}
710712
}
711713

714+
pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
715+
match self {
716+
Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
717+
Some((parameters.as_single(), Rawness::Ref, *mutability))
718+
}
719+
Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => {
720+
Some((parameters.as_single(), Rawness::RawPtr, *mutability))
721+
}
722+
_ => None,
723+
}
724+
}
725+
712726
pub fn strip_references(&self) -> &Ty {
713727
let mut t: &Ty = self;
714728

crates/ra_hir_ty/src/tests/coercion.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() {
116116
assert_snapshot!(
117117
infer(r#"
118118
fn test() {
119-
let x: &[i32] = &[1];
119+
let x: &[isize] = &[1];
120+
let x: *const [isize] = &[1];
120121
}
121122
"#),
122123
@r###"
123-
11..40 '{ ...[1]; }': ()
124-
21..22 'x': &[i32]
125-
33..37 '&[1]': &[i32; _]
126-
34..37 '[1]': [i32; _]
127-
35..36 '1': i32
124+
11..76 '{ ...[1]; }': ()
125+
21..22 'x': &[isize]
126+
35..39 '&[1]': &[isize; _]
127+
36..39 '[1]': [isize; _]
128+
37..38 '1': isize
129+
49..50 'x': *const [isize]
130+
69..73 '&[1]': &[isize; _]
131+
70..73 '[1]': [isize; _]
132+
71..72 '1': isize
128133
"###);
129134
}
130135

crates/ra_hir_ty/src/tests/simple.rs

+20
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
384384
);
385385
}
386386

387+
#[test]
388+
fn infer_raw_ref() {
389+
assert_snapshot!(
390+
infer(r#"
391+
fn test(a: i32) {
392+
&raw mut a;
393+
&raw const a;
394+
}
395+
"#),
396+
@r###"
397+
9..10 'a': i32
398+
17..54 '{ ...t a; }': ()
399+
23..33 '&raw mut a': *mut i32
400+
32..33 'a': i32
401+
39..51 '&raw const a': *const i32
402+
50..51 'a': i32
403+
"###
404+
);
405+
}
406+
387407
#[test]
388408
fn infer_literals() {
389409
assert_snapshot!(

crates/ra_parser/src/grammar/expressions.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -325,13 +325,27 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
325325
let kind = match p.current() {
326326
// test ref_expr
327327
// fn foo() {
328+
// // reference operator
328329
// let _ = &1;
329330
// let _ = &mut &f();
331+
// let _ = &raw;
332+
// let _ = &raw.0;
333+
// // raw reference operator
334+
// let _ = &raw mut foo;
335+
// let _ = &raw const foo;
330336
// }
331337
T![&] => {
332338
m = p.start();
333339
p.bump(T![&]);
334-
p.eat(T![mut]);
340+
if p.at(IDENT)
341+
&& p.at_contextual_kw("raw")
342+
&& (p.nth_at(1, T![mut]) || p.nth_at(1, T![const]))
343+
{
344+
p.bump_remap(T![raw]);
345+
p.bump_any();
346+
} else {
347+
p.eat(T![mut]);
348+
}
335349
REF_EXPR
336350
}
337351
// test unary_expr

crates/ra_syntax/src/ast/generated/nodes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,8 @@ impl CastExpr {
12351235
/// ```
12361236
/// ❰ &foo ❱;
12371237
/// ❰ &mut bar ❱;
1238+
/// ❰ &raw const bar ❱;
1239+
/// ❰ &raw mut bar ❱;
12381240
/// ```
12391241
///
12401242
/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators)
@@ -1247,6 +1249,7 @@ impl RefExpr {
12471249
pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
12481250
pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
12491251
pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
1252+
pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
12501253
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
12511254
}
12521255
/// Prefix operator call. This is either `!` or `*` or `-`.

0 commit comments

Comments
 (0)