Skip to content

Commit

Permalink
Merge #4648
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bors[bot] and robojumper authored May 29, 2020
2 parents 190a059 + 367487f commit 30658b2
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 72 deletions.
19 changes: 16 additions & 3 deletions crates/ra_hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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());
Expand Down
3 changes: 2 additions & 1 deletion crates/ra_hir_def/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down Expand Up @@ -110,6 +110,7 @@ pub enum Expr {
},
Ref {
expr: ExprId,
rawness: Rawness,
mutability: Mutability,
},
Box {
Expand Down
16 changes: 16 additions & 0 deletions crates/ra_hir_def/src/type_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
37 changes: 23 additions & 14 deletions crates/ra_hir_ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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());
Expand Down
18 changes: 16 additions & 2 deletions crates/ra_hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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;

Expand Down
17 changes: 11 additions & 6 deletions crates/ra_hir_ty/src/tests/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
"###);
}

Expand Down
20 changes: 20 additions & 0 deletions crates/ra_hir_ty/src/tests/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
16 changes: 15 additions & 1 deletion crates/ra_parser/src/grammar/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions crates/ra_syntax/src/ast/generated/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 `-`.
Expand Down
Loading

0 comments on commit 30658b2

Please sign in to comment.