Lower unsafety of fn pointer and fn item types

This commit is contained in:
Lukas Wirth 2022-11-04 21:07:15 +01:00
parent 6c3ab563de
commit 6f09c72b1b
6 changed files with 47 additions and 18 deletions

View file

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

View file

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

View file

@ -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, ")")?;

View file

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

View file

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

View file

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