Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support raw_ref_op's raw reference operator #4648

Merged
merged 1 commit into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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