Skip to content

Commit 00c8cab

Browse files
bors[bot]Veykril
andauthored
Merge #9765
9765: internal: Introduce TypeInfo r=Veykril a=Veykril Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents 4b0c976 + b96f1ad commit 00c8cab

32 files changed

+141
-135
lines changed

crates/hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub use crate::{
8989
UnresolvedModule, UnresolvedProcMacro,
9090
},
9191
has_source::HasSource,
92-
semantics::{PathResolution, Semantics, SemanticsScope},
92+
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo},
9393
};
9494

9595
// Be careful with these re-exports.

crates/hir/src/semantics.rs

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,29 @@ impl PathResolution {
8787
}
8888
}
8989

90+
#[derive(Debug)]
91+
pub struct TypeInfo {
92+
/// The original type of the expression or pattern.
93+
pub original: Type,
94+
/// The adjusted type, if an adjustment happened.
95+
pub adjusted: Option<Type>,
96+
}
97+
98+
impl TypeInfo {
99+
pub fn original(self) -> Type {
100+
self.original
101+
}
102+
103+
pub fn has_adjustment(&self) -> bool {
104+
self.adjusted.is_some()
105+
}
106+
107+
/// The adjusted type, or the original in case no adjustments occurred.
108+
pub fn adjusted(self) -> Type {
109+
self.adjusted.unwrap_or(self.original)
110+
}
111+
}
112+
90113
/// Primary API to get semantic information, like types, from syntax trees.
91114
pub struct Semantics<'db, DB> {
92115
pub db: &'db DB,
@@ -212,23 +235,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
212235
self.imp.resolve_type(ty)
213236
}
214237

215-
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
238+
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
216239
self.imp.type_of_expr(expr)
217240
}
218241

219-
/// Returns true in case a coercion happened.
220-
pub fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, bool)> {
221-
self.imp.type_of_expr_with_coercion(expr)
222-
}
223-
224-
pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
242+
pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
225243
self.imp.type_of_pat(pat)
226244
}
227245

228-
pub fn type_of_pat_with_coercion(&self, expr: &ast::Pat) -> Option<(Type, bool)> {
229-
self.imp.type_of_pat_with_coercion(expr)
230-
}
231-
232246
pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
233247
self.imp.type_of_self(param)
234248
}
@@ -565,20 +579,16 @@ impl<'db> SemanticsImpl<'db> {
565579
Type::new_with_resolver(self.db, &scope.resolver, ty)
566580
}
567581

568-
fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
569-
self.analyze(expr.syntax()).type_of_expr(self.db, expr)
570-
}
571-
572-
fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, bool)> {
573-
self.analyze(expr.syntax()).type_of_expr_with_coercion(self.db, expr)
574-
}
575-
576-
fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
577-
self.analyze(pat.syntax()).type_of_pat(self.db, pat)
582+
fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
583+
self.analyze(expr.syntax())
584+
.type_of_expr(self.db, expr)
585+
.map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
578586
}
579587

580-
fn type_of_pat_with_coercion(&self, pat: &ast::Pat) -> Option<(Type, bool)> {
581-
self.analyze(pat.syntax()).type_of_pat_with_coercion(self.db, pat)
588+
fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
589+
self.analyze(pat.syntax())
590+
.type_of_pat(self.db, pat)
591+
.map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
582592
}
583593

584594
fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
@@ -757,7 +767,7 @@ impl<'db> SemanticsImpl<'db> {
757767
ast::Expr::FieldExpr(field_expr) => field_expr,
758768
_ => return None,
759769
};
760-
let ty = self.type_of_expr(&field_expr.expr()?)?;
770+
let ty = self.type_of_expr(&field_expr.expr()?)?.original;
761771
if !ty.is_packed(self.db) {
762772
return None;
763773
}
@@ -784,7 +794,7 @@ impl<'db> SemanticsImpl<'db> {
784794
self.type_of_expr(&expr)
785795
})
786796
// Binding a reference to a packed type is possibly unsafe.
787-
.map(|ty| ty.is_packed(self.db))
797+
.map(|ty| ty.original.is_packed(self.db))
788798
.unwrap_or(false)
789799

790800
// FIXME This needs layout computation to be correct. It will highlight
@@ -830,7 +840,7 @@ impl<'db> SemanticsImpl<'db> {
830840
}
831841
})
832842
// Binding a reference to a packed type is possibly unsafe.
833-
.map(|ty| ty.is_packed(self.db))
843+
.map(|ty| ty.original.is_packed(self.db))
834844
.unwrap_or(false)
835845
}
836846
}

crates/hir/src/source_analyzer.rs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -116,46 +116,36 @@ impl SourceAnalyzer {
116116
Some(res)
117117
}
118118

119-
pub(crate) fn type_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> {
120-
let expr_id = self.expr_id(db, expr)?;
121-
let ty = self.infer.as_ref()?[expr_id].clone();
122-
Type::new_with_resolver(db, &self.resolver, ty)
123-
}
124-
125-
pub(crate) fn type_of_expr_with_coercion(
119+
pub(crate) fn type_of_expr(
126120
&self,
127121
db: &dyn HirDatabase,
128122
expr: &ast::Expr,
129-
) -> Option<(Type, bool)> {
123+
) -> Option<(Type, Option<Type>)> {
130124
let expr_id = self.expr_id(db, expr)?;
131125
let infer = self.infer.as_ref()?;
132-
let (ty, coerced) = infer
126+
let coerced = infer
133127
.expr_adjustments
134128
.get(&expr_id)
135-
.and_then(|adjusts| adjusts.last().map(|adjust| (&adjust.target, true)))
136-
.unwrap_or_else(|| (&infer[expr_id], false));
137-
Type::new_with_resolver(db, &self.resolver, ty.clone()).zip(Some(coerced))
138-
}
139-
140-
pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> {
141-
let pat_id = self.pat_id(pat)?;
142-
let ty = self.infer.as_ref()?[pat_id].clone();
143-
Type::new_with_resolver(db, &self.resolver, ty)
129+
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
130+
let ty = infer[expr_id].clone();
131+
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
132+
mk_ty(ty.clone()).zip(Some(coerced.and_then(mk_ty)))
144133
}
145134

146-
pub(crate) fn type_of_pat_with_coercion(
135+
pub(crate) fn type_of_pat(
147136
&self,
148137
db: &dyn HirDatabase,
149138
pat: &ast::Pat,
150-
) -> Option<(Type, bool)> {
139+
) -> Option<(Type, Option<Type>)> {
151140
let pat_id = self.pat_id(pat)?;
152141
let infer = self.infer.as_ref()?;
153-
let (ty, coerced) = infer
142+
let coerced = infer
154143
.pat_adjustments
155144
.get(&pat_id)
156-
.and_then(|adjusts| adjusts.last().map(|adjust| (&adjust.target, true)))
157-
.unwrap_or_else(|| (&infer[pat_id], false));
158-
Type::new_with_resolver(db, &self.resolver, ty.clone()).zip(Some(coerced))
145+
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
146+
let ty = infer[pat_id].clone();
147+
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
148+
mk_ty(ty.clone()).zip(Some(coerced.and_then(mk_ty)))
159149
}
160150

161151
pub(crate) fn type_of_self(

crates/ide/src/call_hierarchy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
8686
let name_ref = call_node.name_ref()?;
8787
let func_target = match call_node {
8888
FnCallNode::CallExpr(expr) => {
89-
let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
89+
let callable = sema.type_of_expr(&expr.expr()?)?.original.as_callable(db)?;
9090
match callable.kind() {
9191
hir::CallableKind::Function(it) => it.try_to_nav(db),
9292
_ => None,

crates/ide/src/goto_type_definition.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ pub(crate) fn goto_type_definition(
3232
let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
3333
let ty = match_ast! {
3434
match node {
35-
ast::Expr(it) => sema.type_of_expr(&it)?,
36-
ast::Pat(it) => sema.type_of_pat(&it)?,
35+
ast::Expr(it) => sema.type_of_expr(&it)?.original,
36+
ast::Pat(it) => sema.type_of_pat(&it)?.original,
3737
ast::SelfParam(it) => sema.type_of_self(&it)?,
3838
ast::Type(it) => sema.resolve_type(&it)?,
3939
ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,

crates/ide/src/highlight_related.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ fn highlight_exit_points(
123123
}
124124
}
125125
ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroCall(_) => {
126-
if sema.type_of_expr(&expr).map_or(false, |ty| ty.is_never()) {
126+
if sema.type_of_expr(&expr).map_or(false, |ty| ty.original.is_never()) {
127127
highlights
128128
.push(HighlightedRange { access: None, range: expr.syntax().text_range() });
129129
}

crates/ide/src/hover.rs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use either::Either;
2-
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
2+
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
33
use ide_db::{
44
base_db::{FileRange, SourceDatabase},
55
defs::{Definition, NameClass, NameRefClass},
@@ -225,33 +225,29 @@ fn hover_type_info(
225225
config: &HoverConfig,
226226
expr_or_pat: &Either<ast::Expr, ast::Pat>,
227227
) -> Option<HoverResult> {
228-
let (ty, coerced) = match expr_or_pat {
229-
Either::Left(expr) => sema.type_of_expr_with_coercion(expr)?,
230-
Either::Right(pat) => sema.type_of_pat_with_coercion(pat)?,
228+
let TypeInfo { original, adjusted } = match expr_or_pat {
229+
Either::Left(expr) => sema.type_of_expr(expr)?,
230+
Either::Right(pat) => sema.type_of_pat(pat)?,
231231
};
232232

233233
let mut res = HoverResult::default();
234-
res.markup = if coerced {
235-
let uncoerced_ty = match expr_or_pat {
236-
Either::Left(expr) => sema.type_of_expr(expr)?,
237-
Either::Right(pat) => sema.type_of_pat(pat)?,
238-
};
239-
let uncoerced = uncoerced_ty.display(sema.db).to_string();
240-
let coerced = ty.display(sema.db).to_string();
234+
res.markup = if let Some(adjusted_ty) = adjusted {
235+
let original = original.display(sema.db).to_string();
236+
let adjusted = adjusted_ty.display(sema.db).to_string();
241237
format!(
242-
"```text\nType: {:>upad$}\nCoerced to: {:>cpad$}\n```\n",
243-
uncoerced = uncoerced,
244-
coerced = coerced,
238+
"```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n```\n",
239+
uncoerced = original,
240+
coerced = adjusted,
245241
// 6 base padding for static text prefix of each line
246-
upad = 6 + coerced.len().max(uncoerced.len()),
247-
cpad = uncoerced.len(),
242+
apad = 6 + adjusted.len().max(original.len()),
243+
opad = original.len(),
248244
)
249245
.into()
250246
} else {
251247
if config.markdown() {
252-
Markup::fenced_block(&ty.display(sema.db))
248+
Markup::fenced_block(&original.display(sema.db))
253249
} else {
254-
ty.display(sema.db).to_string().into()
250+
original.display(sema.db).to_string().into()
255251
}
256252
};
257253
Some(res)

crates/ide/src/inlay_hints.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use either::Either;
2-
use hir::{known, Callable, HasVisibility, HirDisplay, Semantics};
2+
use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
33
use ide_db::helpers::FamousDefs;
44
use ide_db::RootDatabase;
55
use stdx::to_lower_snake_case;
@@ -117,7 +117,7 @@ fn get_chaining_hints(
117117
next_next = tokens.next()?.kind();
118118
}
119119
if next_next == T![.] {
120-
let ty = sema.type_of_expr(&expr)?;
120+
let ty = sema.type_of_expr(&expr)?.original;
121121
if ty.is_unknown() {
122122
return None;
123123
}
@@ -189,7 +189,7 @@ fn get_bind_pat_hints(
189189
let krate = sema.scope(pat.syntax()).module().map(|it| it.krate());
190190
let famous_defs = FamousDefs(sema, krate);
191191

192-
let ty = sema.type_of_pat(&pat.clone().into())?;
192+
let ty = sema.type_of_pat(&pat.clone().into())?.original;
193193

194194
if should_not_display_type_hint(sema, &pat, &ty) {
195195
return None;
@@ -308,6 +308,7 @@ fn should_not_display_type_hint(
308308
return it.in_token().is_none() ||
309309
it.iterable()
310310
.and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
311+
.map(TypeInfo::original)
311312
.map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
312313
},
313314
_ => (),
@@ -393,7 +394,7 @@ fn is_enum_name_similar_to_param_name(
393394
argument: &ast::Expr,
394395
param_name: &str,
395396
) -> bool {
396-
match sema.type_of_expr(argument).and_then(|t| t.as_adt()) {
397+
match sema.type_of_expr(argument).and_then(|t| t.original.as_adt()) {
397398
Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name,
398399
_ => false,
399400
}
@@ -430,7 +431,7 @@ fn get_callable(
430431
) -> Option<(hir::Callable, ast::ArgList)> {
431432
match expr {
432433
ast::Expr::CallExpr(expr) => {
433-
sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db).zip(expr.arg_list())
434+
sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list())
434435
}
435436
ast::Expr::MethodCallExpr(expr) => {
436437
sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())

crates/ide/src/syntax_highlighting/highlight.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub(super) fn element(
123123
let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
124124

125125
let expr = prefix_expr.expr()?;
126-
let ty = sema.type_of_expr(&expr)?;
126+
let ty = sema.type_of_expr(&expr)?.original;
127127
if ty.is_raw_ptr() {
128128
HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
129129
} else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
@@ -555,7 +555,7 @@ fn highlight_method_call(
555555
if let Some(receiver_ty) =
556556
method_call.receiver().and_then(|it| sema.type_of_expr(&it))
557557
{
558-
if !receiver_ty.is_copy(sema.db) {
558+
if !receiver_ty.adjusted().is_copy(sema.db) {
559559
h |= HlMod::Consuming
560560
}
561561
}

crates/ide_assists/src/handlers/add_explicit_type.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
5454
}
5555

5656
let ty = match (pat, expr) {
57-
(ast::Pat::IdentPat(_), Some(expr)) => ctx.sema.type_of_expr_with_coercion(&expr)?.0,
57+
(ast::Pat::IdentPat(_), Some(expr)) => ctx.sema.type_of_expr(&expr)?,
5858
(pat, _) => ctx.sema.type_of_pat(&pat)?,
59-
};
59+
}
60+
.adjusted();
6061

6162
// Unresolved or unnameable types can't be annotated
6263
if ty.contains_unknown() || ty.is_closure() {

0 commit comments

Comments
 (0)