From 6f09c72b1b26bc11c401d734f4ae9d9e8f8de565 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Nov 2022 21:07:15 +0100 Subject: [PATCH] Lower unsafety of fn pointer and fn item types --- crates/hir-def/src/pretty.rs | 5 ++++- crates/hir-def/src/type_ref.rs | 6 +++--- crates/hir-ty/src/display.rs | 7 +++++-- crates/hir-ty/src/lib.rs | 21 ++++++++++++++++----- crates/hir-ty/src/lower.rs | 19 ++++++++++++++----- crates/hir-ty/src/tests/coercion.rs | 7 +++++-- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index 6636c8a23ca..933970d10e4 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 5b4c71be7fb..f8bb78ddcfe 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, ConstScalarOrPath), Slice(Box), /// A fn pointer. Last element of the vector is the return type. - Fn(Vec<(Option, TypeRef)>, bool /*varargs*/), + Fn(Vec<(Option, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/), ImplTrait(Vec>), DynTrait(Vec>), Macro(AstId), @@ -229,7 +229,7 @@ pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self { 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 @@ pub fn walk(&self, f: &mut impl FnMut(&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 5ad66132635..a22a4b170f6 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -1187,8 +1187,11 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { 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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { 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 2b5989c6c6f..b68c764bdca 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -210,6 +210,7 @@ pub(crate) fn make_binders>( pub struct CallableSig { params_and_return: Arc<[Ty]>, is_varargs: bool, + safety: Safety, } has_interner!(CallableSig); @@ -218,9 +219,14 @@ pub struct CallableSig { pub type PolyFnSig = Binders; impl CallableSig { - pub fn from_params_and_return(mut params: Vec, ret: Ty, is_varargs: bool) -> CallableSig { + pub fn from_params_and_return( + mut params: Vec, + 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 @@ pub fn from_fn_ptr(fn_ptr: &FnPointer) -> 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 @@ fn try_fold_with( ) -> Result { 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 22a85cf1545..baf9842d5fb 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -227,13 +227,17 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { .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::>(); 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::>(); 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 1abdb0be7f8..7e3aecc2ae0 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)) }", ); }