Add flag to disallow opaque types for DisplayTarget::SourceCode

This commit is contained in:
Ryo Yoshida 2023-04-07 22:45:04 +09:00
parent 7501d3b721
commit ac03de773f
No known key found for this signature in database
GPG key ID: E25698A930586171
15 changed files with 62 additions and 29 deletions

View file

@ -150,6 +150,7 @@ pub trait HirDisplay {
&'a self,
db: &'a dyn HirDatabase,
module_id: ModuleId,
allow_opaque: bool,
) -> Result<String, DisplaySourceCodeError> {
let mut result = String::new();
match self.hir_fmt(&mut HirFormatter {
@ -160,7 +161,7 @@ pub trait HirDisplay {
max_size: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::SourceCode { module_id },
display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
}) {
Ok(()) => {}
Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@ -249,18 +250,26 @@ pub enum DisplayTarget {
Diagnostics,
/// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified.
SourceCode { module_id: ModuleId },
SourceCode { module_id: ModuleId, allow_opaque: bool },
/// Only for test purpose to keep real types
Test,
}
impl DisplayTarget {
fn is_source_code(&self) -> bool {
fn is_source_code(self) -> bool {
matches!(self, Self::SourceCode { .. })
}
fn is_test(&self) -> bool {
fn is_test(self) -> bool {
matches!(self, Self::Test)
}
fn allows_opaque(self) -> bool {
match self {
Self::SourceCode { allow_opaque, .. } => allow_opaque,
_ => true,
}
}
}
#[derive(Debug)]
@ -268,6 +277,7 @@ pub enum DisplaySourceCodeError {
PathNotFound,
UnknownType,
Generator,
OpaqueType,
}
pub enum HirDisplayError {
@ -768,7 +778,7 @@ impl HirDisplay for Ty {
};
write!(f, "{name}")?;
}
DisplayTarget::SourceCode { module_id } => {
DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
if let Some(path) = find_path::find_path(
db.upcast(),
ItemInNs::Types((*def_id).into()),
@ -906,6 +916,11 @@ impl HirDisplay for Ty {
f.end_location_link();
}
TyKind::OpaqueType(opaque_ty_id, parameters) => {
if !f.display_target.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
}
let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
match impl_trait_id {
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
@ -953,8 +968,14 @@ impl HirDisplay for Ty {
}
}
TyKind::Closure(id, substs) => {
if f.display_target.is_source_code() && f.closure_style != ClosureStyle::ImplFn {
never!("Only `impl Fn` is valid for displaying closures in source code");
if f.display_target.is_source_code() {
if !f.display_target.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
} else if f.closure_style != ClosureStyle::ImplFn {
never!("Only `impl Fn` is valid for displaying closures in source code");
}
}
match f.closure_style {
ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
@ -1053,6 +1074,11 @@ impl HirDisplay for Ty {
}
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
if !f.display_target.allows_opaque() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::OpaqueType,
));
}
let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
match impl_trait_id {
ImplTraitId::ReturnTypeImplTrait(func, idx) => {

View file

@ -159,7 +159,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
let range = node.as_ref().original_file_range(&db);
if let Some(expected) = types.remove(&range) {
let actual = if display_source {
ty.display_source_code(&db, def.module(&db)).unwrap()
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db).to_string()
};
@ -175,7 +175,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
let range = node.as_ref().original_file_range(&db);
if let Some(expected) = types.remove(&range) {
let actual = if display_source {
ty.display_source_code(&db, def.module(&db)).unwrap()
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db).to_string()
};

View file

@ -69,7 +69,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
return None;
}
let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
let inferred_type = ty.display_source_code(ctx.db(), module.into(), false).ok()?;
acc.add(
AssistId("add_explicit_type", AssistKind::RefactorRewrite),
format!("Insert explicit type `{inferred_type}`"),

View file

@ -22,7 +22,7 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
if ty.is_unit() {
return None;
}
let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;
let ty = ty.display_source_code(ctx.db(), module.into(), true).ok()?;
acc.add(
AssistId("add_return_type", AssistKind::RefactorRewrite),

View file

@ -1884,7 +1884,7 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr
}
fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String {
ty.display_source_code(ctx.db(), module.into()).ok().unwrap_or_else(|| "_".to_string())
ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_string())
}
fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {

View file

@ -46,7 +46,8 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
let ty = ctx.sema.type_of_expr(&expr)?;
let scope = ctx.sema.scope(statement.syntax())?;
let constant_module = scope.module();
let type_name = ty.original().display_source_code(ctx.db(), constant_module.into()).ok()?;
let type_name =
ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?;
let target = statement.syntax().parent()?.text_range();
let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?;

View file

@ -192,7 +192,7 @@ fn expr_ty(
scope: &hir::SemanticsScope<'_>,
) -> Option<ast::Type> {
let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?;
let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?;
let text = ty.display_source_code(ctx.db(), scope.module().into(), false).ok()?;
Some(make::ty(&text))
}

View file

@ -438,7 +438,7 @@ fn make_return_type(
Some(ty) if ty.is_unit() => (None, false),
Some(ty) => {
necessary_generic_params.extend(ty.generic_params(ctx.db()));
let rendered = ty.display_source_code(ctx.db(), target_module.into());
let rendered = ty.display_source_code(ctx.db(), target_module.into(), true);
match rendered {
Ok(rendered) => (Some(make::ty(&rendered)), false),
Err(_) => (Some(make::ty_placeholder()), true),
@ -992,9 +992,9 @@ fn fn_arg_type(
let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
.map(|conversion| conversion.convert_type(ctx.db()))
.or_else(|| ty.display_source_code(ctx.db(), target_module.into()).ok())
.or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
} else {
ty.display_source_code(ctx.db(), target_module.into()).ok()
ty.display_source_code(ctx.db(), target_module.into(), true).ok()
}
}

View file

@ -57,11 +57,13 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
let local = ctx.sema.to_def(&pat)?;
let ty = ctx.sema.type_of_pat(&pat.into())?.original;
if ty.contains_unknown() || ty.is_closure() {
cov_mark::hit!(promote_lcoal_not_applicable_if_ty_not_inferred);
return None;
}
let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;
let ty = match ty.display_source_code(ctx.db(), module.into(), false) {
Ok(ty) => ty,
Err(_) => {
cov_mark::hit!(promote_local_not_applicable_if_ty_not_inferred);
return None;
}
};
let initializer = let_stmt.initializer()?;
if !is_body_const(&ctx.sema, &initializer) {
@ -187,7 +189,7 @@ fn foo() {
#[test]
fn not_applicable_unknown_ty() {
cov_mark::check!(promote_lcoal_not_applicable_if_ty_not_inferred);
cov_mark::check!(promote_local_not_applicable_if_ty_not_inferred);
check_assist_not_applicable(
promote_local_to_const,
r"

View file

@ -55,7 +55,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
let returned_type = match ctx.sema.type_of_expr(&initializer) {
Some(returned_type) if !returned_type.original.contains_unknown() => {
let module = ctx.sema.scope(let_stmt.syntax())?.module();
returned_type.original.display_source_code(ctx.db(), module.into()).ok()?
returned_type.original.display_source_code(ctx.db(), module.into(), false).ok()?
}
_ => {
cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available);

View file

@ -127,7 +127,7 @@ fn params_from_stmt_list_scope(
let module = scope.module().into();
scope.process_all_names(&mut |name, def| {
if let hir::ScopeDef::Local(local) = def {
if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module) {
if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true) {
cb(name, ty);
}
}

View file

@ -242,7 +242,7 @@ pub(crate) fn complete_ascribed_type(
}
}?
.adjusted();
let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?;
let ty_string = x.display_source_code(ctx.db, ctx.module.into(), true).ok()?;
acc.add(render_type_inference(ty_string, ctx));
None
}

View file

@ -116,7 +116,9 @@ impl<'a> PathTransform<'a> {
Some((
k,
ast::make::ty(
&default.display_source_code(db, source_module.into()).ok()?,
&default
.display_source_code(db, source_module.into(), false)
.ok()?,
),
))
}

View file

@ -176,7 +176,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
fn make_ty(ty: &hir::Type, db: &dyn HirDatabase, module: hir::Module) -> ast::Type {
let ty_str = match ty.as_adt() {
Some(adt) => adt.name(db).to_string(),
None => ty.display_source_code(db, module.into()).ok().unwrap_or_else(|| "_".to_string()),
None => {
ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_string())
}
};
make::ty(&ty_str)

View file

@ -69,7 +69,7 @@ fn missing_record_expr_field_fixes(
let new_field = make::record_field(
None,
make::name(record_expr_field.field_name()?.ident_token()?.text()),
make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?),
);
let last_field = record_fields.fields().last()?;