Unnamed repository; edit this file 'description' to name the repository.
Lower unsafety of fn pointer and fn item types
Lukas Wirth 2022-11-05
parent 6c3ab56 · commit 6f09c72
-rw-r--r--crates/hir-def/src/pretty.rs5
-rw-r--r--crates/hir-def/src/type_ref.rs6
-rw-r--r--crates/hir-ty/src/display.rs7
-rw-r--r--crates/hir-ty/src/lib.rs21
-rw-r--r--crates/hir-ty/src/lower.rs19
-rw-r--r--crates/hir-ty/src/tests/coercion.rs7
6 files changed, 47 insertions, 18 deletions
diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs
index 6636c8a23c..933970d10e 100644
--- a/crates/hir-def/src/pretty.rs
+++ b/crates/hir-def/src/pretty.rs
@@ -143,9 +143,12 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re
print_type_ref(elem, buf)?;
write!(buf, "]")?;
}
- TypeRef::Fn(args_and_ret, varargs) => {
+ TypeRef::Fn(args_and_ret, varargs, is_unsafe) => {
let ((_, return_type), args) =
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
+ if *is_unsafe {
+ write!(buf, "unsafe ")?;
+ }
write!(buf, "fn(")?;
for (i, (_, typeref)) in args.iter().enumerate() {
if i != 0 {
diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/type_ref.rs
index 5b4c71be7f..f8bb78ddcf 100644
--- a/crates/hir-def/src/type_ref.rs
+++ b/crates/hir-def/src/type_ref.rs
@@ -119,7 +119,7 @@ pub enum TypeRef {
Array(Box<TypeRef>, ConstScalarOrPath),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
- Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
+ Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/),
ImplTrait(Vec<Interned<TypeBound>>),
DynTrait(Vec<Interned<TypeBound>>),
Macro(AstId<ast::MacroCall>),
@@ -229,7 +229,7 @@ impl TypeRef {
Vec::new()
};
params.push((None, ret_ty));
- TypeRef::Fn(params, is_varargs)
+ TypeRef::Fn(params, is_varargs, inner.unsafe_token().is_some())
}
// for types are close enough for our purposes to the inner type for now...
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
@@ -263,7 +263,7 @@ impl TypeRef {
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
f(type_ref);
match type_ref {
- TypeRef::Fn(params, _) => {
+ TypeRef::Fn(params, _, _) => {
params.iter().for_each(|(_, param_type)| go(param_type, f))
}
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 5ad6613263..a22a4b170f 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1187,8 +1187,11 @@ impl HirDisplay for TypeRef {
inner.hir_fmt(f)?;
write!(f, "]")?;
}
- TypeRef::Fn(parameters, is_varargs) => {
+ &TypeRef::Fn(ref parameters, is_varargs, is_unsafe) => {
// FIXME: Function pointer qualifiers.
+ if is_unsafe {
+ write!(f, "unsafe ")?;
+ }
write!(f, "fn(")?;
if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
for index in 0..function_parameters.len() {
@@ -1203,7 +1206,7 @@ impl HirDisplay for TypeRef {
write!(f, ", ")?;
}
}
- if *is_varargs {
+ if is_varargs {
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
}
write!(f, ")")?;
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 2b5989c6c6..b68c764bdc 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -210,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
pub struct CallableSig {
params_and_return: Arc<[Ty]>,
is_varargs: bool,
+ safety: Safety,
}
has_interner!(CallableSig);
@@ -218,9 +219,14 @@ has_interner!(CallableSig);
pub type PolyFnSig = Binders<CallableSig>;
impl CallableSig {
- pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
+ pub fn from_params_and_return(
+ mut params: Vec<Ty>,
+ ret: Ty,
+ is_varargs: bool,
+ safety: Safety,
+ ) -> CallableSig {
params.push(ret);
- CallableSig { params_and_return: params.into(), is_varargs }
+ CallableSig { params_and_return: params.into(), is_varargs, safety }
}
pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
@@ -237,13 +243,14 @@ impl CallableSig {
.map(|arg| arg.assert_ty_ref(Interner).clone())
.collect(),
is_varargs: fn_ptr.sig.variadic,
+ safety: fn_ptr.sig.safety,
}
}
pub fn to_fn_ptr(&self) -> FnPointer {
FnPointer {
num_binders: 0,
- sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
+ sig: FnSig { abi: (), safety: self.safety, variadic: self.is_varargs },
substitution: FnSubst(Substitution::from_iter(
Interner,
self.params_and_return.iter().cloned(),
@@ -268,7 +275,11 @@ impl TypeFoldable<Interner> for CallableSig {
) -> Result<Self, E> {
let vec = self.params_and_return.to_vec();
let folded = vec.try_fold_with(folder, outer_binder)?;
- Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
+ Ok(CallableSig {
+ params_and_return: folded.into(),
+ is_varargs: self.is_varargs,
+ safety: self.safety,
+ })
}
}
@@ -573,5 +584,5 @@ pub fn callable_sig_from_fnonce(
let ret_ty = db.normalize_projection(projection, env);
- Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false))
+ Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false, Safety::Safe))
}
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 22a85cf154..baf9842d5f 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -227,13 +227,17 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner)
}
TypeRef::Placeholder => TyKind::Error.intern(Interner),
- TypeRef::Fn(params, is_varargs) => {
+ &TypeRef::Fn(ref params, variadic, is_unsafe) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
- sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
+ sig: FnSig {
+ abi: (),
+ safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
+ variadic,
+ },
substitution: FnSubst(substs),
})
.intern(Interner)
@@ -1573,7 +1577,12 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
.with_type_param_mode(ParamLoweringMode::Variable);
let ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into());
- let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
+ let sig = CallableSig::from_params_and_return(
+ params,
+ ret,
+ data.is_varargs(),
+ if data.has_unsafe_kw() { Safety::Unsafe } else { Safety::Safe },
+ );
make_binders(db, &generics, sig)
}
@@ -1617,7 +1626,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
- Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+ Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}
/// Build the type of a tuple struct constructor.
@@ -1644,7 +1653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
- Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+ Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}
/// Build the type of a tuple enum variant constructor.
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index 1abdb0be7f..7e3aecc2ae 100644
--- a/crates/hir-ty/src/tests/coercion.rs
+++ b/crates/hir-ty/src/tests/coercion.rs
@@ -390,7 +390,7 @@ fn test() {
let f: fn(u32) -> isize = foo;
// ^^^ adjustments: Pointer(ReifyFnPointer)
let f: unsafe fn(u32) -> isize = foo;
- // ^^^ adjustments: Pointer(ReifyFnPointer)
+ // ^^^ adjustments: Pointer(ReifyFnPointer), Pointer(UnsafeFnPointer)
}",
);
}
@@ -421,7 +421,10 @@ fn coerce_closure_to_fn_ptr() {
check_no_mismatches(
r"
fn test() {
- let f: fn(u32) -> isize = |x| { 1 };
+ let f: fn(u32) -> u32 = |x| x;
+ // ^^^^^ adjustments: Pointer(ClosureFnPointer(Safe))
+ let f: unsafe fn(u32) -> u32 = |x| x;
+ // ^^^^^ adjustments: Pointer(ClosureFnPointer(Unsafe))
}",
);
}