Skip to content

Commit 5939ef1

Browse files
Diagnose trait errors
I.e. type does not implement trait. There are a lot of other solver errors to be emitted, and the error is pretty simple currently, but this is a huge step!
1 parent d82a3e7 commit 5939ef1

44 files changed

Lines changed: 1405 additions & 232 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/hir-def/src/attrs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: ast::Meta) -> ControlFlow<
263263
}
264264
_ => {}
265265
},
266+
"diagnostic" => match &*second_segment {
267+
"do_not_recommend" => {
268+
attr_flags.insert(AttrFlags::DIAGNOSTIC_DO_NOT_RECOMMEND)
269+
}
270+
_ => {}
271+
},
266272
_ => {}
267273
},
268274
}
@@ -335,6 +341,8 @@ bitflags::bitflags! {
335341
const MACRO_STYLE_PARENTHESES = 1 << 48;
336342

337343
const PREFER_UNDERSCORE_IMPORT = 1 << 49;
344+
345+
const DIAGNOSTIC_DO_NOT_RECOMMEND = 1 << 50;
338346
}
339347
}
340348

crates/hir-def/src/expr_store/lower/format_args.rs

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ impl<'db> ExprCollector<'db> {
3030
) -> ExprId {
3131
let mut args = FormatArgumentsCollector::default();
3232
f.args().for_each(|arg| {
33+
let expr = arg.expr();
3334
args.add(FormatArgument {
3435
kind: match arg.arg_name() {
3536
Some(name) => FormatArgumentKind::Named(Name::new_root(name.name().text())),
3637
None => FormatArgumentKind::Normal,
3738
},
38-
expr: self.collect_expr_opt(arg.expr()),
39+
syntax: expr.as_ref().map(AstPtr::new),
40+
expr: self.collect_expr_opt(expr),
3941
});
4042
});
4143
let template = f.template();
@@ -53,8 +55,10 @@ impl<'db> ExprCollector<'db> {
5355
Some(((s, is_direct_literal), template)) => {
5456
let call_ctx = SyntaxContext::root(self.def_map.edition());
5557
let hygiene = self.hygiene_id_for(s.syntax().text_range());
58+
let template_ptr = AstPtr::new(&template);
5659
let fmt = format_args::parse(
5760
&s,
61+
template_ptr,
5862
fmt_snippet,
5963
args,
6064
is_direct_literal,
@@ -65,10 +69,7 @@ impl<'db> ExprCollector<'db> {
6569
.template_map
6670
.get_or_insert_with(Default::default)
6771
.implicit_capture_to_source
68-
.insert(
69-
expr_id,
70-
self.expander.in_file((AstPtr::new(&template), range)),
71-
);
72+
.insert(expr_id, self.expander.in_file((template_ptr, range)));
7273
}
7374
if !hygiene.is_root() {
7475
self.store.ident_hygiene.insert(expr_id.into(), hygiene);
@@ -340,7 +341,8 @@ impl<'db> ExprCollector<'db> {
340341
expr: args_ident_expr,
341342
name: Name::new_tuple_field(arg_index),
342343
});
343-
self.make_argument(arg, ty)
344+
let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax);
345+
self.make_argument(arg_ptr, arg, ty)
344346
})
345347
.collect();
346348
let args =
@@ -557,7 +559,8 @@ impl<'db> ExprCollector<'db> {
557559
rawness: Rawness::Ref,
558560
mutability: Mutability::Shared,
559561
});
560-
self.make_argument(arg, ty)
562+
let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax);
563+
self.make_argument(arg_ptr, arg, ty)
561564
})
562565
.collect();
563566
let array =
@@ -649,7 +652,8 @@ impl<'db> ExprCollector<'db> {
649652
rawness: Rawness::Ref,
650653
mutability: Mutability::Shared,
651654
});
652-
self.make_argument(ref_arg, ty)
655+
let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax);
656+
self.make_argument(arg_ptr, ref_arg, ty)
653657
})
654658
.collect();
655659
let args =
@@ -716,7 +720,8 @@ impl<'db> ExprCollector<'db> {
716720
expr: args_ident_expr,
717721
name: Name::new_tuple_field(arg_index),
718722
});
719-
self.make_argument(arg, ty)
723+
let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax);
724+
self.make_argument(arg_ptr, arg, ty)
720725
})
721726
.collect();
722727
let array =
@@ -976,11 +981,16 @@ impl<'db> ExprCollector<'db> {
976981
/// ```text
977982
/// <core::fmt::Argument>::new_…(arg)
978983
/// ```
979-
fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
984+
fn make_argument(
985+
&mut self,
986+
arg_ptr: Option<AstPtr<ast::Expr>>,
987+
arg: ExprId,
988+
ty: ArgumentType,
989+
) -> ExprId {
980990
use ArgumentType::*;
981991
use FormatTrait::*;
982992

983-
let new_fn = self.ty_rel_lang_path_desugared_expr(
993+
let new_fn = self.ty_rel_lang_path(
984994
self.lang_items().FormatArgument,
985995
match ty {
986996
Format(Display) => sym::new_display,
@@ -995,6 +1005,22 @@ impl<'db> ExprCollector<'db> {
9951005
Usize => sym::from_usize,
9961006
},
9971007
);
1008+
let new_fn = match new_fn {
1009+
Some(new_fn) => {
1010+
let new_fn = self.store.exprs.alloc(Expr::Path(new_fn));
1011+
if let Some(arg_ptr) = arg_ptr {
1012+
// Trait errors (the argument does not implement the expected fmt trait) will show
1013+
// on this path, so to not end up with synthetic syntax we insert this mapping. We
1014+
// don't want to insert the other way's mapping in order to not override the source
1015+
// for the argument.
1016+
self.store
1017+
.expr_map_back
1018+
.insert(new_fn, self.expander.in_file(arg_ptr.wrap_left()));
1019+
}
1020+
new_fn
1021+
}
1022+
None => self.missing_expr(),
1023+
};
9981024
self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
9991025
}
10001026

crates/hir-def/src/hir/format_args.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_parse_format as parse;
77
use span::SyntaxContext;
88
use stdx::TupleExt;
99
use syntax::{
10-
TextRange,
10+
AstPtr, TextRange,
1111
ast::{self, IsString},
1212
};
1313

@@ -146,6 +146,7 @@ pub enum FormatCount {
146146
pub struct FormatArgument {
147147
pub kind: FormatArgumentKind,
148148
pub expr: ExprId,
149+
pub syntax: Option<AstPtr<ast::Expr>>,
149150
}
150151

151152
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -171,6 +172,7 @@ use PositionUsedAs::*;
171172
#[allow(clippy::unnecessary_lazy_evaluations)]
172173
pub(crate) fn parse(
173174
s: &ast::String,
175+
string_ptr: AstPtr<ast::Expr>,
174176
fmt_snippet: Option<String>,
175177
mut args: FormatArgumentsCollector,
176178
is_direct_literal: bool,
@@ -273,6 +275,11 @@ pub(crate) fn parse(
273275
// FIXME: This is problematic, we might want to synthesize a dummy
274276
// expression proper and/or desugar these.
275277
expr: synth(name, span),
278+
// FIXME: This will lead us to show failed trait bounds (e.g. `T: Display`)
279+
// on the whole template string for implicit arguments instead of just their name.
280+
// Fixing this is hard since we don't have an `AstPtr` for the arg, and it's
281+
// only part of an expression.
282+
syntax: Some(string_ptr),
276283
}))
277284
}
278285
}

crates/hir-expand/src/files.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ impl ErasedAstId {
128128
}
129129
}
130130

131+
impl<FileKind, N: AstNode> InFileWrapper<FileKind, AstPtr<N>> {
132+
#[inline]
133+
pub fn upcast<M: AstNode>(self) -> InFileWrapper<FileKind, AstPtr<M>>
134+
where
135+
N: Into<M>,
136+
{
137+
self.map(|it| it.upcast())
138+
}
139+
}
140+
131141
impl<FileKind, T> InFileWrapper<FileKind, T> {
132142
pub fn new(file_id: FileKind, value: T) -> Self {
133143
Self { file_id, value }

crates/hir-ty/src/diagnostics/expr.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ impl<'db> ExprValidator<'db> {
177177
}
178178
// Check that the number of arguments matches the number of parameters.
179179

180-
if self.infer.expr_type_mismatches().next().is_some() {
180+
if self.infer.exprs_have_type_mismatches() {
181181
// FIXME: Due to shortcomings in the current type system implementation, only emit
182182
// this diagnostic if there are no type mismatches in the containing function.
183183
} else if let Expr::MethodCall { receiver, .. } = expr {
@@ -331,7 +331,7 @@ impl<'db> ExprValidator<'db> {
331331
let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
332332
continue;
333333
};
334-
if self.infer.type_mismatch_for_pat(pat).is_some() {
334+
if self.infer.pat_has_type_mismatch(pat) {
335335
continue;
336336
}
337337
let Some(initializer) = initializer else { continue };
@@ -628,13 +628,13 @@ pub fn record_pattern_missing_fields(
628628

629629
fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool {
630630
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
631-
match infer.type_mismatch_for_pat(pat) {
632-
Some(_) => *has_type_mismatches = true,
633-
None if *has_type_mismatches => (),
634-
None => {
631+
match infer.pat_has_type_mismatch(pat) {
632+
true => *has_type_mismatches = true,
633+
false if *has_type_mismatches => (),
634+
false => {
635635
let pat = &body[pat];
636636
if let Pat::ConstBlock(expr) | Pat::Lit(expr) = *pat {
637-
*has_type_mismatches |= infer.type_mismatch_for_expr(expr).is_some();
637+
*has_type_mismatches |= infer.expr_has_type_mismatch(expr);
638638
if *has_type_mismatches {
639639
return;
640640
}

crates/hir-ty/src/display.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ use crate::{
5959
next_solver::{
6060
AliasTy, Allocation, Clause, ClauseKind, Const, ConstKind, DbInterner,
6161
ExistentialPredicate, FnSig, GenericArg, GenericArgKind, GenericArgs, ParamEnv, PolyFnSig,
62-
Region, SolverDefId, StoredEarlyBinder, StoredTy, Term, TermKind, TraitRef, Ty, TyKind,
63-
TypingMode, ValTree,
62+
Region, SolverDefId, StoredEarlyBinder, StoredTy, Term, TermKind, TraitPredicate, TraitRef,
63+
Ty, TyKind, TypingMode, ValTree,
6464
abi::Safety,
6565
infer::{DbInternerInferExt, traits::ObligationCause},
6666
},
@@ -2291,6 +2291,23 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> {
22912291
}
22922292
}
22932293

2294+
impl<'db> HirDisplay<'db> for TraitPredicate<'db> {
2295+
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2296+
self.self_ty().hir_fmt(f)?;
2297+
f.write_str(": ")?;
2298+
match self.polarity {
2299+
rustc_type_ir::PredicatePolarity::Positive => {}
2300+
rustc_type_ir::PredicatePolarity::Negative => f.write_char('!')?,
2301+
}
2302+
let trait_ = self.def_id().0;
2303+
f.start_location_link(trait_.into());
2304+
write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2305+
f.end_location_link();
2306+
let substs = &self.trait_ref.args[1..];
2307+
hir_fmt_generic_args(f, substs, None, None)
2308+
}
2309+
}
2310+
22942311
impl<'db> HirDisplay<'db> for Region<'db> {
22952312
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
22962313
match self.kind() {

0 commit comments

Comments
 (0)