diff --git a/.github/ISSUE_TEMPLATE/diagnostics.md b/.github/ISSUE_TEMPLATE/diagnostics.md deleted file mode 100644 index a7b70cea927d0..0000000000000 --- a/.github/ISSUE_TEMPLATE/diagnostics.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: Diagnostic issue -about: Create a bug report or feature request for a change to `rustc`'s error output -labels: A-diagnostics, T-compiler ---- - - -Given the following code: - -```rust - -``` - -The current output is: - -``` - -``` - - -Ideally the output should look like: - -``` - -``` - - - - diff --git a/.github/ISSUE_TEMPLATE/diagnostics.yaml b/.github/ISSUE_TEMPLATE/diagnostics.yaml new file mode 100644 index 0000000000000..873fbaaf654fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/diagnostics.yaml @@ -0,0 +1,65 @@ +name: Diagnostic issue +description: Create a bug report or feature request for a change to `rustc`'s error output +labels: ["A-diagnostics", "T-compiler"] +body: + - type: markdown + attributes: + value: | + Thank you for filing a diagnostics bug report! 🐛 + + Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. + + If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur. + - type: textarea + id: code + attributes: + label: Code + description: Please provide code that can reproduce the problem + placeholder: code + render: Rust + validations: + required: true + - type: textarea + id: output + attributes: + label: Current output + description: Please provide the `rustc` output you see + placeholder: rustc output + render: Shell + validations: + required: true + - type: textarea + id: desired-output + attributes: + label: Desired output + description: Please provide what the output *should* be + placeholder: proposed output + render: Shell + validations: + required: false + - type: textarea + id: rationale + attributes: + label: Rationale and extra context + description: If the problem is not self-explanatory, please provide a rationale for the change. + validations: + required: false + - type: textarea + id: other-output + attributes: + label: Other cases + description: If dramatically different output is caused by small changes, consider also adding them here. + render: Rust + validations: + required: false + - type: markdown + attributes: + value: | + If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition. + - type: textarea + id: extra + attributes: + label: Anything else? + description: If you have more details you want to give us to reproduce this issue, please add it here + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index 9ccda17a6ef47..0000000000000 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: Documentation problem -about: Create a report for a documentation problem. -labels: A-docs ---- - - -### Location - -### Summary diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml new file mode 100644 index 0000000000000..712b32759ae01 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yaml @@ -0,0 +1,38 @@ +name: Documentation problem +description: Create a report for a documentation problem. +labels: ["A-docs"] +body: + - type: markdown + attributes: + value: | + Thank you for finding a documentation problem! 📚 + + Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present. + + Note: If your issue is for one of these, please use their dedicated issue tracker instead: + - [The Rust Book](https://github.com/rust-lang/book/issues) + - [Rust by Example](https://github.com/rust-lang/rust-by-example/issues) + - [The Edition Guide](https://github.com/rust-lang/edition-guide/issues) + - [The Cargo Book](https://github.com/rust-lang/cargo/issues) + - [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues) + - [The Reference](https://github.com/rust-lang/reference/issues) + - [The Rustonomicon](https://github.com/rust-lang/nomicon/issues) + - [The Embedded Book](https://github.com/rust-embedded/book/issues) + + All other documentation issues should be filed here. + + Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead. + + - type: textarea + id: location + attributes: + label: Location + validations: + required: true + + - type: textarea + id: summary + attributes: + label: Summary + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/ice.md b/.github/ISSUE_TEMPLATE/ice.md deleted file mode 100644 index 03bc4bab45137..0000000000000 --- a/.github/ISSUE_TEMPLATE/ice.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: Internal Compiler Error -about: Create a report for an internal compiler error in rustc. -labels: C-bug, I-ICE, T-compiler ---- - - -### Code - -```Rust - -``` - - -### Meta - - -`rustc --version --verbose`: -``` - -``` - -### Error output - -``` - -``` - - -
Backtrace -

- -``` - -``` - -

-
- diff --git a/.github/ISSUE_TEMPLATE/ice.yaml b/.github/ISSUE_TEMPLATE/ice.yaml new file mode 100644 index 0000000000000..54136cc6d439d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ice.yaml @@ -0,0 +1,82 @@ +name: Internal Compiler Error +description: Create a report for an internal compiler error in `rustc` +labels: ["C-bug", "I-ICE", "T-compiler"] +title: "[ICE]: " +body: + - type: markdown + attributes: + value: | + Thank you for finding an Internal Compiler Error! 🧊 + + If possible, try to provide a minimal verifiable example. + + You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples. + + - type: textarea + id: code + attributes: + label: Code + description: Please provide code or a link to a repository that can reproduce the problem + placeholder: code + render: Rust + validations: + required: false + + - type: checkboxes + attributes: + label: Affected release channels + description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions + options: + - label: Previous Stable + required: false + - label: Current Stable + required: false + - label: Current Beta + required: false + - label: Current Nightly + required: false + + - type: textarea + id: version + attributes: + label: Rust Version + description: Please provide the `rustc` version, `rustc --version --verbose` + placeholder: | + $ rustc --version --verbose + rustc 1.XX.Y (SHORTHASH DATE) + binary: rustc + commit-hash: LONGHASHVALUE + commit-date: DATE + host: PLATFORMTRIPLE + release: 1.XX.Y + LLVM version: XX.YY.ZZ + render: Shell + validations: + required: true + + - type: textarea + id: output + attributes: + label: Current error output + description: Please provide the `rustc` output you see + placeholder: output + render: Shell + validations: + required: false + + - type: textarea + id: backtrace + attributes: + label: Backtrace + description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build` + render: Shell + validations: + required: true + + - type: textarea + id: extra + attributes: + label: Anything else? + description: If you have more details you want to give us to reproduce this issue, please add it here + validations: + required: false \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ee91b00377182..5511d30177559 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5601,6 +5601,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ + "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.14.0", "ignore", "lazy_static", diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 6c128d0aa1a65..665dc8b6a2f2a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.note_internal_mutation_in_method(err, expr, expected, expr_ty); self.check_for_range_as_method_call(err, expr, expr_ty, expected); self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected); + self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty); } /// Requires that the two types unify, and prints an error message if @@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(block.span, "this block is missing a tail expression"); } } + + fn check_wrong_return_type_due_to_generic_arg( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + checked_ty: Ty<'tcx>, + ) { + let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; }; + enum CallableKind { + Function, + Method, + Constructor, + } + let mut maybe_emit_help = |def_id: hir::def_id::DefId, + callable: rustc_span::symbol::Ident, + args: &[hir::Expr<'_>], + kind: CallableKind| { + let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap(); + let fn_ty = self.tcx.bound_type_of(def_id).0; + if !fn_ty.is_fn() { + return; + } + let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder(); + let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; }; + if matches!(arg.kind(), ty::Param(_)) + && fn_sig.output().contains(arg) + && self.node_ty(args[arg_idx].hir_id) == checked_ty + { + let mut multi_span: MultiSpan = parent_expr.span.into(); + multi_span.push_span_label( + args[arg_idx].span, + format!( + "this argument influences the {} of `{}`", + if matches!(kind, CallableKind::Constructor) { + "type" + } else { + "return type" + }, + callable + ), + ); + err.span_help( + multi_span, + format!( + "the {} `{}` due to the type of the argument passed", + match kind { + CallableKind::Function => "return type of this call is", + CallableKind::Method => "return type of this call is", + CallableKind::Constructor => "type constructed contains", + }, + checked_ty + ), + ); + } + }; + match parent_expr.kind { + hir::ExprKind::Call(fun, args) => { + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; }; + let hir::def::Res::Def(kind, def_id) = path.res else { return; }; + let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { + CallableKind::Constructor + } else { + CallableKind::Function + }; + maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind); + } + hir::ExprKind::MethodCall(method, _receiver, args, _span) => { + let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; }; + maybe_emit_help(def_id, method.ident, args, CallableKind::Method) + } + _ => return, + } + } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index dd827777df94e..15f6e11717768 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push(( - o.predicate, - None, - Some(o.cause), - )); + let parent_o = o.clone(); + let implied_obligations = + traits::elaborate_obligations(self.tcx, vec![o]); + for o in implied_obligations { + let parent = if o == parent_o { + None + } else { + if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id()) + == self.tcx.lang_items().sized_trait() + { + // We don't care to talk about implicit `Sized` bounds. + continue; + } + Some(parent_o.predicate) + }; + if !self.predicate_may_hold(&o) { + possibly_unsatisfied_predicates.push(( + o.predicate, + parent, + Some(o.cause), + )); + } + } } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8166eb8299041..f49fde04e8444 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => None, }; - if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { - if let Some(g) = kind.generics() { - let key = ( - g.tail_span_for_predicate_suggestion(), - g.add_where_or_trailing_comma(), - ); - type_params - .entry(key) - .or_insert_with(FxHashSet::default) - .insert(obligation.to_owned()); - } + if let Some(hir::Node::Item(hir::Item { kind, .. })) = node + && let Some(g) = kind.generics() + { + let key = ( + g.tail_span_for_predicate_suggestion(), + g.add_where_or_trailing_comma(), + ); + type_params + .entry(key) + .or_insert_with(FxHashSet::default) + .insert(obligation.to_owned()); + return true; } } + false }; let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let msg = format!( @@ -692,7 +694,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "auto trait is invoked with no method error, but no error reported?", ); } - Some(_) => unreachable!(), + Some(Node::Item(hir::Item { + ident, kind: hir::ItemKind::Trait(..), .. + })) => { + skip_list.insert(p); + let entry = spanned_predicates.entry(ident.span); + let entry = entry.or_insert_with(|| { + (FxHashSet::default(), FxHashSet::default(), Vec::new()) + }); + entry.0.insert(cause.span); + entry.1.insert((ident.span, "")); + entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + entry.2.push(p); + } + Some(node) => unreachable!("encountered `{node:?}`"), None => (), } } @@ -719,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds = true; } + let mut suggested_bounds = FxHashSet::default(); // The requirements that didn't have an `impl` span to show. let mut bound_list = unsatisfied_predicates .iter() .filter_map(|(pred, parent_pred, _cause)| { + let mut suggested = false; format_pred(*pred).map(|(p, self_ty)| { - collect_type_param_suggestions(self_ty, *pred, &p); + if let Some(parent) = parent_pred && suggested_bounds.contains(parent) { + // We don't suggest `PartialEq` when we already suggest `Eq`. + } else if !suggested_bounds.contains(pred) { + if collect_type_param_suggestions(self_ty, *pred, &p) { + suggested = true; + suggested_bounds.insert(pred); + } + } ( match parent_pred { None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { None => format!("`{}`", &p), Some((parent_p, _)) => { - collect_type_param_suggestions(self_ty, *parent_pred, &p); + if !suggested + && !suggested_bounds.contains(pred) + && !suggested_bounds.contains(parent_pred) + { + if collect_type_param_suggestions( + self_ty, + *parent_pred, + &p, + ) { + suggested_bounds.insert(pred); + } + } format!("`{}`\nwhich is required by `{}`", p, parent_p) } }, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8f0bd3a9abe5e..1817bbf922854 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{self, Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::{self, ToPredicate, TyCtxt}; use rustc_span::symbol::Ident; @@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { + let obligations = predicates.predicates.iter().map(|&(mut pred, span)| { // when parent predicate is non-const, elaborate it to non-const predicates. if data.constness == ty::BoundConstness::NotConst { pred = pred.without_const(tcx); } + let cause = obligation.cause.clone().derived_cause( + bound_predicate.rebind(data), + |derived| { + traits::ImplDerivedObligation(Box::new( + traits::ImplDerivedObligationCause { + derived, + impl_def_id: data.def_id(), + span, + }, + )) + }, + ); predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, - obligation.cause.clone(), + cause, ) }); debug!(?data, ?obligations, "super_predicates"); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f027843e6b43d..8761c23625b21 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -79,7 +79,7 @@ impl<'a> StringReader<'a> { /// preceded by whitespace. fn next_token(&mut self) -> (Token, bool) { let mut preceded_by_whitespace = false; - + let mut swallow_next_invalid = 0; // Skip trivial (whitespace & comments) tokens loop { let token = self.cursor.advance_token(); @@ -232,19 +232,34 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => { - let c = self.str_from(start).chars().next().unwrap(); + // Don't emit diagnostics for sequences of the same invalid token + if swallow_next_invalid > 0 { + swallow_next_invalid -= 1; + continue; + } + let mut it = self.str_from_to_end(start).chars(); + let c = it.next().unwrap(); + let repeats = it.take_while(|c1| *c1 == c).count(); let mut err = - self.struct_err_span_char(start, self.pos, "unknown start of token", c); + self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c); // FIXME: the lexer could be used to turn the ASCII version of unicode // homoglyphs, instead of keeping a table in `check_for_substitution`into the // token. Ideally, this should be inside `rustc_lexer`. However, we should // first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this // way. - let token = unicode_chars::check_for_substitution(self, start, c, &mut err); + let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1); if c == '\x00' { err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used"); } + if repeats > 0 { + if repeats == 1 { + err.note(format!("character appears once more")); + } else { + err.note(format!("character appears {repeats} more times")); + } + swallow_next_invalid = repeats; + } err.emit(); if let Some(token) = token { token @@ -486,6 +501,11 @@ impl<'a> StringReader<'a> { &self.src[self.src_index(start)..self.src_index(end)] } + /// Slice of the source text spanning from `start` until the end + fn str_from_to_end(&self, start: BytePos) -> &str { + &self.src[self.src_index(start)..] + } + fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! { match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) { Err(RawStrError::InvalidStarter { bad_char }) => { diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index f1b50296e2565..65479b341d7a8 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -337,10 +337,11 @@ pub(super) fn check_for_substitution<'a>( pos: BytePos, ch: char, err: &mut Diagnostic, + count: usize, ) -> Option { let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?; - let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8())); + let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count)); let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else { let msg = format!("substitution character not found for '{}'", ch); @@ -369,7 +370,12 @@ pub(super) fn check_for_substitution<'a>( "Unicode character '{}' ({}) looks like '{}' ({}), but it is not", ch, u_name, ascii_char, ascii_name ); - err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect); + err.span_suggestion( + span, + &msg, + ascii_char.to_string().repeat(count), + Applicability::MaybeIncorrect, + ); } token.clone() } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index dd2b03988c3e8..645f863394105 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr { pub(super) enum LhsExpr { NotYetParsed, AttributesParsed(AttrWrapper), - AlreadyParsed(P, bool), // (expr, starts_statement) + AlreadyParsed { expr: P, starts_statement: bool }, } impl From> for LhsExpr { @@ -97,11 +97,11 @@ impl From> for LhsExpr { } impl From> for LhsExpr { - /// Converts the `expr: P` into `LhsExpr::AlreadyParsed(expr)`. + /// Converts the `expr: P` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`. /// /// This conversion does not allocate. fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed(expr, false) + LhsExpr::AlreadyParsed { expr, starts_statement: false } } } @@ -174,7 +174,7 @@ impl<'a> Parser<'a> { lhs: LhsExpr, ) -> PResult<'a, P> { let mut starts_stmt = false; - let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs { + let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs { starts_stmt = starts_statement; expr } else { @@ -562,17 +562,23 @@ impl<'a> Parser<'a> { // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() match this.token.uninterpolate().kind { - token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr` - token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr` + // `!expr` + token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), + // `~expr` + token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), + // `-expr` token::BinOp(token::Minus) => { make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg)) - } // `-expr` + } + // `*expr` token::BinOp(token::Star) => { make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref)) - } // `*expr` + } + // `&expr` and `&&expr` token::BinOp(token::And) | token::AndAnd => { make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo)) } + // `+lit` token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { let mut err = LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None }; @@ -587,7 +593,7 @@ impl<'a> Parser<'a> { this.bump(); this.parse_prefix_expr(None) - } // `+expr` + } // Recover from `++x`: token::BinOp(token::Plus) if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) => @@ -624,7 +630,7 @@ impl<'a> Parser<'a> { Ok((span, self.mk_unary(op, expr))) } - // Recover on `!` suggesting for bitwise negation instead. + /// Recover on `~expr` in favor of `!expr`. fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { self.sess.emit_err(TildeAsUnaryOperator(lo)); @@ -651,7 +657,6 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - // Emit the error... let negated_token = self.look_ahead(1, |t| t.clone()); let sub_diag = if negated_token.is_numeric_lit() { @@ -672,7 +677,6 @@ impl<'a> Parser<'a> { ), }); - // ...and recover! self.parse_unary_expr(lo, UnOp::Not) } @@ -1593,7 +1597,7 @@ impl<'a> Parser<'a> { vis.0 }; - // Suggestion involves adding a (as of time of writing this, unstable) labeled block. + // Suggestion involves adding a labeled block. // // If there are no breaks that may use this label, suggest removing the label and // recover to the unmodified expression. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1e5c283496035..4ff9927aab51a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,7 +164,10 @@ impl<'a> Parser<'a> { // Perform this outside of the `collect_tokens_trailing_token` closure, // since our outer attributes do not apply to this part of the expression let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true)) + this.parse_assoc_expr_with( + 0, + LhsExpr::AlreadyParsed { expr, starts_statement: true }, + ) })?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } else { @@ -198,7 +201,10 @@ impl<'a> Parser<'a> { let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?; + let e = self.parse_assoc_expr_with( + 0, + LhsExpr::AlreadyParsed { expr: e, starts_statement: false }, + )?; StmtKind::Expr(e) }; Ok(self.mk_stmt(lo.to(hi), kind)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0c7ffb056cc02..41a64a844ce49 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -374,6 +374,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } } + impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( &self, @@ -852,6 +853,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut suggested = self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(trait_predicate); + suggested = if let &[cand] = &impl_candidates[..] { + let cand = cand.trait_ref; + if let (ty::FnPtr(_), ty::FnDef(..)) = + (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) + { + err.span_suggestion( + span.shrink_to_hi(), + format!( + "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", + cand.print_only_trait_path(), + cand.self_ty(), + ), + format!(" as {}", cand.self_ty()), + Applicability::MaybeIncorrect, + ); + true + } else { + false + } + } else { + false + } || suggested; suggested |= self.suggest_remove_reference(&obligation, &mut err, trait_predicate); suggested |= self.suggest_semicolon_removal( @@ -1968,27 +1992,25 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { candidates.sort(); candidates.dedup(); let len = candidates.len(); - if candidates.len() == 0 { + if candidates.is_empty() { return false; } - if candidates.len() == 1 { - let ty_desc = match candidates[0].self_ty().kind() { - ty::FnPtr(_) => Some("fn pointer"), - _ => None, - }; - let the_desc = match ty_desc { - Some(desc) => format!(" implemented for {} `", desc), - None => " implemented for `".to_string(), - }; + if let &[cand] = &candidates[..] { + let (desc, mention_castable) = + match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) { + (ty::FnPtr(_), ty::FnDef(..)) => { + (" implemented for fn pointer `", ", cast using `as`") + } + (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""), + _ => (" implemented for `", ""), + }; err.highlighted_help(vec![ - ( - format!("the trait `{}` ", candidates[0].print_only_trait_path()), - Style::NoStyle, - ), + (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), ("is".to_string(), Style::Highlight), - (the_desc, Style::NoStyle), - (candidates[0].self_ty().to_string(), Style::Highlight), + (desc.to_string(), Style::NoStyle), + (cand.self_ty().to_string(), Style::Highlight), ("`".to_string(), Style::NoStyle), + (mention_castable.to_string(), Style::NoStyle), ]); return true; } diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 67cee0148b24e..5fbce36c39d28 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0 +git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index fff83a1d097b3..19812fc6f55b6 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -6,6 +6,7 @@ autobins = false [dependencies] cargo_metadata = "0.14" +cargo-platform = "0.1.2" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } lazy_static = "1" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 845eb5af0d6bb..bc2edf634de2b 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,7 +1,7 @@ //! Checks the licenses of third-party dependencies. -use cargo_metadata::{Metadata, Package, PackageId, Resolve}; -use std::collections::{BTreeSet, HashSet}; +use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId}; +use std::collections::HashSet; use std::path::Path; /// These are licenses that are allowed for all crates, including the runtime, @@ -98,14 +98,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "autocfg", "bitflags", "block-buffer", - "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown. "cc", "cfg-if", "chalk-derive", "chalk-engine", "chalk-ir", "chalk-solve", - "chrono", "convert_case", // dependency of derive_more "compiler_builtins", "cpufeatures", @@ -124,11 +122,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "dlmalloc", "either", "ena", - "env_logger", "expect-test", "fallible-iterator", // dependency of `thorin` "fastrand", - "filetime", "fixedbitset", "flate2", "fluent-bundle", @@ -142,13 +138,11 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "gsgdt", "hashbrown", "hermit-abi", - "humantime", "icu_list", "icu_locid", "icu_provider", "icu_provider_adapters", "icu_provider_macros", - "if_chain", "indexmap", "instant", "intl-memoizer", @@ -156,7 +150,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "itertools", "itoa", "jobserver", - "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown. "lazy_static", "libc", "libloading", @@ -171,8 +164,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "memmap2", "memoffset", "miniz_oxide", - "num-integer", - "num-traits", "num_cpus", "object", "odht", @@ -190,7 +181,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "proc-macro2", "psm", "punycode", - "quick-error", "quote", "rand", "rand_chacha", @@ -235,7 +225,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "thiserror-impl", "thorin-dwp", "thread_local", - "time", "tinystr", "tinyvec", "tinyvec_macros", @@ -268,13 +257,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "valuable", "version_check", "wasi", - // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown. - "wasm-bindgen", - "wasm-bindgen-backend", - "wasm-bindgen-macro", - "wasm-bindgen-macro-support", - "wasm-bindgen-shared", - // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown. "winapi", "winapi-i686-pc-windows-gnu", "winapi-util", @@ -485,73 +467,55 @@ fn check_permitted_dependencies( restricted_dependency_crates: &[&'static str], bad: &mut bool, ) { + let mut deps = HashSet::new(); + for to_check in restricted_dependency_crates { + let to_check = pkg_from_name(metadata, to_check); + use cargo_platform::Cfg; + use std::str::FromStr; + // We don't expect the compiler to ever run on wasm32, so strip + // out those dependencies to avoid polluting the permitted list. + deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| { + dep_kinds.iter().any(|dep_kind| { + dep_kind + .target + .as_ref() + .map(|target| { + !target.matches( + "wasm32-unknown-unknown", + &[ + Cfg::from_str("target_arch=\"wasm32\"").unwrap(), + Cfg::from_str("target_os=\"unknown\"").unwrap(), + ], + ) + }) + .unwrap_or(true) + }) + }); + } + // Check that the PERMITTED_DEPENDENCIES does not have unused entries. - for name in permitted_dependencies { - if !metadata.packages.iter().any(|p| p.name == *name) { + for permitted in permitted_dependencies { + if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) { tidy_error!( bad, - "could not find allowed package `{}`\n\ + "could not find allowed package `{permitted}`\n\ Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", - name ); } } - // Get the list in a convenient form. - let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect(); - - // Check dependencies. - let mut visited = BTreeSet::new(); - let mut unapproved = BTreeSet::new(); - for &krate in restricted_dependency_crates.iter() { - let pkg = pkg_from_name(metadata, krate); - let mut bad = - check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg); - unapproved.append(&mut bad); - } - - if !unapproved.is_empty() { - tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr); - for dep in unapproved { - println!("* {dep}"); - } - } -} - -/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on -/// the list of permitted dependencies. Returns a list of disallowed dependencies. -fn check_crate_dependencies<'a>( - permitted_dependencies: &'a HashSet<&'static str>, - metadata: &'a Metadata, - visited: &mut BTreeSet<&'a PackageId>, - krate: &'a Package, -) -> BTreeSet<&'a PackageId> { - // This will contain bad deps. - let mut unapproved = BTreeSet::new(); - - // Check if we have already visited this crate. - if visited.contains(&krate.id) { - return unapproved; - } - visited.insert(&krate.id); + // Get in a convenient form. + let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect(); - // If this path is in-tree, we don't require it to be explicitly permitted. - if krate.source.is_some() { - // If this dependency is not on `PERMITTED_DEPENDENCIES`, add to bad set. - if !permitted_dependencies.contains(krate.name.as_str()) { - unapproved.insert(&krate.id); + for dep in deps { + let dep = pkg_from_id(metadata, dep); + // If this path is in-tree, we don't require it to be explicitly permitted. + if dep.source.is_some() { + if !permitted_dependencies.contains(dep.name.as_str()) { + tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); + } } } - - // Do a DFS in the crate graph. - let to_check = deps_of(metadata, &krate.id); - - for dep in to_check { - let mut bad = check_crate_dependencies(permitted_dependencies, metadata, visited, dep); - unapproved.append(&mut bad); - } - - unapproved } /// Prevents multiple versions of some expensive crates. @@ -588,24 +552,6 @@ fn check_crate_duplicate( } } -/// Returns a list of dependencies for the given package. -fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> { - let resolve = metadata.resolve.as_ref().unwrap(); - let node = resolve - .nodes - .iter() - .find(|n| &n.id == pkg_id) - .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve")); - node.deps - .iter() - .map(|dep| { - metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| { - panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id) - }) - }) - .collect() -} - /// Finds a package with the given name. fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package { let mut i = metadata.packages.iter().filter(|p| p.name == name); @@ -615,41 +561,57 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package result } +fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package { + metadata.packages.iter().find(|p| &p.id == id).unwrap() +} + /// Finds all the packages that are in the rust runtime. fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> { - let resolve = metadata.resolve.as_ref().unwrap(); let mut result = HashSet::new(); for name in RUNTIME_CRATES { let id = &pkg_from_name(metadata, name).id; - normal_deps_of_r(resolve, id, &mut result); + deps_of_filtered(metadata, id, &mut result, &|_| true); } result } -/// Recursively find all normal dependencies. -fn normal_deps_of_r<'a>( - resolve: &'a Resolve, +/// Recursively find all dependencies. +fn deps_of_filtered<'a>( + metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>, + filter: &dyn Fn(&[DepKindInfo]) -> bool, ) { if !result.insert(pkg_id) { return; } - let node = resolve + let node = metadata + .resolve + .as_ref() + .unwrap() .nodes .iter() .find(|n| &n.id == pkg_id) .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve")); for dep in &node.deps { - normal_deps_of_r(resolve, &dep.pkg, result); + if !filter(&dep.dep_kinds) { + continue; + } + deps_of_filtered(metadata, &dep.pkg, result, filter); } } +fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> { + let resolve = metadata.resolve.as_ref().unwrap(); + let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap(); + node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect() +} + fn check_rustfix(metadata: &Metadata, bad: &mut bool) { let cargo = pkg_from_name(metadata, "cargo"); let compiletest = pkg_from_name(metadata, "compiletest"); - let cargo_deps = deps_of(metadata, &cargo.id); - let compiletest_deps = deps_of(metadata, &compiletest.id); + let cargo_deps = direct_deps_of(metadata, &cargo.id); + let compiletest_deps = direct_deps_of(metadata, &compiletest.id); let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap(); let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap(); if cargo_rustfix.version != compiletest_rustfix.version { diff --git a/tests/mir-opt/building/custom/consts.rs b/tests/mir-opt/building/custom/consts.rs index ff4fe1a93246e..16d10eb5968c1 100644 --- a/tests/mir-opt/building/custom/consts.rs +++ b/tests/mir-opt/building/custom/consts.rs @@ -18,8 +18,8 @@ fn consts() { }) } -static S: i32 = 5; -static mut T: i32 = 10; +static S: i32 = 0x05050505; +static mut T: i32 = 0x0a0a0a0a; // EMIT_MIR consts.statics.built.after.mir #[custom_mir(dialect = "built")] fn statics() { diff --git a/tests/mir-opt/building/custom/consts.statics.built.after.mir b/tests/mir-opt/building/custom/consts.statics.built.after.mir index ee768e263ecdf..bfef976aa0272 100644 --- a/tests/mir-opt/building/custom/consts.statics.built.after.mir +++ b/tests/mir-opt/building/custom/consts.statics.built.after.mir @@ -19,9 +19,9 @@ fn statics() -> () { } alloc2 (static: T, size: 4, align: 4) { - 0a 00 00 00 │ .... + 0a 0a 0a 0a │ .... } alloc1 (static: S, size: 4, align: 4) { - 05 00 00 00 │ .... + 05 05 05 05 │ .... } diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index b9d551c5e5fc2..7fa29cccd50d6 100644 --- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -38,6 +38,6 @@ } alloc1 (static: STATIC, size: 4, align: 4) { - 2a 00 00 00 │ *... + 42 42 42 42 │ BBBB } diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs index 8c23c5fcf0f88..b69ec931a6311 100644 --- a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs +++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs @@ -1,7 +1,7 @@ // unit-test // compile-flags: -O -static mut STATIC: u32 = 42; +static mut STATIC: u32 = 0x42424242; // EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff fn main() { diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index 1c69a6232d606..93804780371cd 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -26,7 +26,7 @@ _3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 // mir::Constant - // + span: $DIR/issue_75439.rs:7:37: 7:46 + // + span: $DIR/issue_75439.rs:8:37: 8:46 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value() } } @@ -49,7 +49,7 @@ _6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 _5 = transmute::(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 // mir::Constant - // + span: $DIR/issue_75439.rs:10:23: 10:32 + // + span: $DIR/issue_75439.rs:11:23: 11:32 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::}, val: Value() } } diff --git a/tests/mir-opt/issues/issue_75439.rs b/tests/mir-opt/issues/issue_75439.rs index ae2e036312e88..4c749a150c091 100644 --- a/tests/mir-opt/issues/issue_75439.rs +++ b/tests/mir-opt/issues/issue_75439.rs @@ -1,4 +1,5 @@ // EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff +// ignore-endian-big use std::mem::transmute; diff --git a/tests/rustdoc-ui/invalid-syntax.stderr b/tests/rustdoc-ui/invalid-syntax.stderr index 597d19e748cb7..6140a06c555f2 100644 --- a/tests/rustdoc-ui/invalid-syntax.stderr +++ b/tests/rustdoc-ui/invalid-syntax.stderr @@ -77,8 +77,6 @@ LL | /// ``` | ^^^ | = note: error from rustc: unknown start of token: ` - = note: error from rustc: unknown start of token: ` - = note: error from rustc: unknown start of token: ` warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:64:5 diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr index f1677b822b4c9..50fa7d1ac4d43 100644 --- a/tests/ui/associated-types/issue-43784-associated-type.stderr +++ b/tests/ui/associated-types/issue-43784-associated-type.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | type Assoc = T; | ^ the trait `Copy` is not implemented for `T` | +note: required for `::Assoc` to implement `Partial` + --> $DIR/issue-43784-associated-type.rs:1:11 + | +LL | pub trait Partial: Copy { + | ^^^^^^^ note: required by a bound in `Complete::Assoc` --> $DIR/issue-43784-associated-type.rs:5:17 | diff --git a/tests/ui/closures/issue-84128.stderr b/tests/ui/closures/issue-84128.stderr index 59607afec8f8d..1cd8949b8c4b7 100644 --- a/tests/ui/closures/issue-84128.stderr +++ b/tests/ui/closures/issue-84128.stderr @@ -6,6 +6,13 @@ LL | Foo(()) | | | arguments to this struct are incorrect | +help: the type constructed contains `()` due to the type of the argument passed + --> $DIR/issue-84128.rs:13:9 + | +LL | Foo(()) + | ^^^^--^ + | | + | this argument influences the type of `Foo` note: tuple struct defined here --> $DIR/issue-84128.rs:5:8 | diff --git a/tests/ui/closures/issue-87461.stderr b/tests/ui/closures/issue-87461.stderr index 72337892734e6..b492251c01691 100644 --- a/tests/ui/closures/issue-87461.stderr +++ b/tests/ui/closures/issue-87461.stderr @@ -6,6 +6,13 @@ LL | Ok(()) | | | arguments to this enum variant are incorrect | +help: the type constructed contains `()` due to the type of the argument passed + --> $DIR/issue-87461.rs:10:5 + | +LL | Ok(()) + | ^^^--^ + | | + | this argument influences the type of `Ok` note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -17,6 +24,13 @@ LL | Ok(()) | | | arguments to this enum variant are incorrect | +help: the type constructed contains `()` due to the type of the argument passed + --> $DIR/issue-87461.rs:17:5 + | +LL | Ok(()) + | ^^^--^ + | | + | this argument influences the type of `Ok` note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -28,6 +42,13 @@ LL | Ok(()) | | | arguments to this enum variant are incorrect | +help: the type constructed contains `()` due to the type of the argument passed + --> $DIR/issue-87461.rs:26:9 + | +LL | Ok(()) + | ^^^--^ + | | + | this argument influences the type of `Ok` note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index bf0bb3fbdf8f7..af03f0e5e5f43 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -6,12 +6,15 @@ LL | struct Value(u32); | | | doesn't satisfy `Value: Eq` | doesn't satisfy `Value: Hash` + | doesn't satisfy `Value: PartialEq` ... LL | hs.insert(Value(0)); | ^^^^^^ | = note: the following trait bounds were not satisfied: `Value: Eq` + `Value: PartialEq` + which is required by `Value: Eq` `Value: Hash` help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` | @@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq` + | -------------------- + | | + | doesn't satisfy `NoDerives: Eq` + | doesn't satisfy `NoDerives: PartialEq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -37,6 +43,9 @@ LL | impl Object { | ^^ --------- | | | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialEq` + which is required by `NoDerives: Eq` help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` | LL | #[derive(Eq, PartialEq)] @@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Ord` + | -------------------- + | | + | doesn't satisfy `NoDerives: Eq` + | doesn't satisfy `NoDerives: Ord` + | doesn't satisfy `NoDerives: PartialEq` + | doesn't satisfy `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -61,6 +75,13 @@ LL | impl Object { | ^^^ --------- | | | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialOrd` + which is required by `NoDerives: Ord` + `NoDerives: PartialEq` + which is required by `NoDerives: Ord` + `NoDerives: Eq` + which is required by `NoDerives: Ord` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] @@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object(T); @@ -91,6 +114,13 @@ LL | impl Object { | | | | | unsatisfied trait bound introduced here | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialEq` + which is required by `NoDerives: Ord` + `NoDerives: Eq` + which is required by `NoDerives: Ord` + `NoDerives: PartialEq` + which is required by `NoDerives: PartialOrd` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] diff --git a/tests/ui/generic-associated-types/issue-74824.stderr b/tests/ui/generic-associated-types/issue-74824.stderr index 623adb1c2ad1e..e5638d90ee8e7 100644 --- a/tests/ui/generic-associated-types/issue-74824.stderr +++ b/tests/ui/generic-associated-types/issue-74824.stderr @@ -17,6 +17,7 @@ LL | type Copy: Copy = Box; | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Box` to implement `Clone` + = note: required for `::Copy` to implement `Copy` note: required by a bound in `UnsafeCopy::Copy` --> $DIR/issue-74824.rs:6:19 | diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr index c913483a8747c..9f669b9a5214b 100644 --- a/tests/ui/generic-associated-types/missing-bounds.stderr +++ b/tests/ui/generic-associated-types/missing-bounds.stderr @@ -23,6 +23,13 @@ LL | A(self.0 + rhs.0) | = note: expected type parameter `B` found associated type `::Output` +help: the type constructed contains `::Output` due to the type of the argument passed + --> $DIR/missing-bounds.rs:11:9 + | +LL | A(self.0 + rhs.0) + | ^^--------------^ + | | + | this argument influences the type of `A` note: tuple struct defined here --> $DIR/missing-bounds.rs:5:8 | diff --git a/tests/ui/mismatched_types/issue-35030.stderr b/tests/ui/mismatched_types/issue-35030.stderr index 680aff1726f9f..de4e067fead4c 100644 --- a/tests/ui/mismatched_types/issue-35030.stderr +++ b/tests/ui/mismatched_types/issue-35030.stderr @@ -11,6 +11,13 @@ LL | Some(true) | = note: expected type parameter `bool` (type parameter `bool`) found type `bool` (`bool`) +help: the type constructed contains `bool` due to the type of the argument passed + --> $DIR/issue-35030.rs:9:9 + | +LL | Some(true) + | ^^^^^----^ + | | + | this argument influences the type of `Some` note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index a2201b946a6f0..05d3de80d8449 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -6,6 +6,8 @@ LL | this.is_subset(other) | = note: the following trait bounds were not satisfied: `T: Eq` + `T: PartialEq` + which is required by `T: Eq` `T: Hash` help: consider restricting the type parameters to satisfy the trait bounds | diff --git a/tests/ui/parser/issues/issue-66473.stderr b/tests/ui/parser/issues/issue-66473.stderr index 8a16d7f955129..0e8b0a5da2205 100644 Binary files a/tests/ui/parser/issues/issue-66473.stderr and b/tests/ui/parser/issues/issue-66473.stderr differ diff --git a/tests/ui/parser/issues/issue-68629.stderr b/tests/ui/parser/issues/issue-68629.stderr index b2c7dddc8011c..43a903e6c4698 100644 Binary files a/tests/ui/parser/issues/issue-68629.stderr and b/tests/ui/parser/issues/issue-68629.stderr differ diff --git a/tests/ui/parser/issues/issue-68730.stderr b/tests/ui/parser/issues/issue-68730.stderr index 6585a19d954ef..5bca5bbebeacb 100644 Binary files a/tests/ui/parser/issues/issue-68730.stderr and b/tests/ui/parser/issues/issue-68730.stderr differ diff --git a/tests/ui/parser/unicode-chars.rs b/tests/ui/parser/unicode-chars.rs index 89ae85ec99027..ba35e95c82a49 100644 --- a/tests/ui/parser/unicode-chars.rs +++ b/tests/ui/parser/unicode-chars.rs @@ -2,4 +2,8 @@ fn main() { let y = 0; //~^ ERROR unknown start of token: \u{37e} //~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not +     let x = 0; + //~^ ERROR unknown start of token: \u{a0} + //~^^ NOTE character appears 3 more times + //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not } diff --git a/tests/ui/parser/unicode-chars.stderr b/tests/ui/parser/unicode-chars.stderr index 0cfe9240e8514..6a5b27872e738 100644 --- a/tests/ui/parser/unicode-chars.stderr +++ b/tests/ui/parser/unicode-chars.stderr @@ -9,5 +9,17 @@ help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), b LL | let y = 0; | ~ -error: aborting due to previous error +error: unknown start of token: \u{a0} + --> $DIR/unicode-chars.rs:5:5 + | +LL |     let x = 0; + | ^^^^ + | + = note: character appears 3 more times +help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not + | +LL | let x = 0; + | ++++ + +error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr index 44a39efdf2542..bc097bf6eb451 100644 --- a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -11,6 +11,13 @@ LL | let _: Option<(i32, bool)> = Some(1, 2); | ^ = note: expected tuple `(i32, bool)` found type `{integer}` +help: the type constructed contains `{integer}` due to the type of the argument passed + --> $DIR/args-instead-of-tuple-errors.rs:6:34 + | +LL | let _: Option<(i32, bool)> = Some(1, 2); + | ^^^^^-^^^^ + | | + | this argument influences the type of `Some` note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL help: remove the extra argument @@ -64,6 +71,13 @@ LL | let _: Option<(i32,)> = Some(5_usize); | = note: expected tuple `(i32,)` found type `usize` +help: the type constructed contains `usize` due to the type of the argument passed + --> $DIR/args-instead-of-tuple-errors.rs:14:29 + | +LL | let _: Option<(i32,)> = Some(5_usize); + | ^^^^^-------^ + | | + | this argument influences the type of `Some` note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -77,6 +91,13 @@ LL | let _: Option<(i32,)> = Some((5_usize)); | = note: expected tuple `(i32,)` found type `usize` +help: the type constructed contains `usize` due to the type of the argument passed + --> $DIR/args-instead-of-tuple-errors.rs:17:29 + | +LL | let _: Option<(i32,)> = Some((5_usize)); + | ^^^^^---------^ + | | + | this argument influences the type of `Some` note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/suggestions/sugg-else-for-closure.stderr b/tests/ui/suggestions/sugg-else-for-closure.stderr index 5f59d0f541c99..7f05832bcd728 100644 --- a/tests/ui/suggestions/sugg-else-for-closure.stderr +++ b/tests/ui/suggestions/sugg-else-for-closure.stderr @@ -8,6 +8,13 @@ LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap()); | = note: expected reference `&str` found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` +help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed + --> $DIR/sugg-else-for-closure.rs:6:14 + | +LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap()); + | ^^^^^^^^^^^^-------------------------------^ + | | + | this argument influences the return type of `unwrap_or` note: associated function defined here --> $SRC_DIR/core/src/option.rs:LL:COL help: try calling `unwrap_or_else` instead diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.rs b/tests/ui/traits/fn-trait-cast-diagnostic.rs new file mode 100644 index 0000000000000..e20aa210e58bd --- /dev/null +++ b/tests/ui/traits/fn-trait-cast-diagnostic.rs @@ -0,0 +1,26 @@ +// There are two different instances to check that even if +// the trait is implemented for the output of a function, +// it will still be displayed if the function itself implements a trait. +trait Foo {} + +impl Foo for fn() -> bool {} +impl Foo for bool {} + +fn example() -> bool { + true +} + +trait NoOtherFoo {} + +impl NoOtherFoo for fn() -> bool {} + +fn do_on_foo(v: impl Foo) {} +fn do_on_single_foo(v: impl NoOtherFoo) {} + +fn main() { + do_on_foo(example); + //~^ ERROR the trait bound + + do_on_single_foo(example); + //~^ ERROR the trait bound +} diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.stderr b/tests/ui/traits/fn-trait-cast-diagnostic.stderr new file mode 100644 index 0000000000000..6851dcdd504d1 --- /dev/null +++ b/tests/ui/traits/fn-trait-cast-diagnostic.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `fn() -> bool {example}: Foo` is not satisfied + --> $DIR/fn-trait-cast-diagnostic.rs:21:15 + | +LL | do_on_foo(example); + | --------- ^^^^^^^ the trait `Foo` is not implemented for fn item `fn() -> bool {example}` + | | + | required by a bound introduced by this call + | +note: required by a bound in `do_on_foo` + --> $DIR/fn-trait-cast-diagnostic.rs:17:22 + | +LL | fn do_on_foo(v: impl Foo) {} + | ^^^ required by this bound in `do_on_foo` +help: use parentheses to call this function + | +LL | do_on_foo(example()); + | ++ +help: the trait `Foo` is implemented for fn pointer `fn() -> bool`, try casting using `as` + | +LL | do_on_foo(example as fn() -> bool); + | +++++++++++++++ + +error[E0277]: the trait bound `fn() -> bool {example}: NoOtherFoo` is not satisfied + --> $DIR/fn-trait-cast-diagnostic.rs:24:22 + | +LL | do_on_single_foo(example); + | ---------------- ^^^^^^^ the trait `NoOtherFoo` is not implemented for fn item `fn() -> bool {example}` + | | + | required by a bound introduced by this call + | +note: required by a bound in `do_on_single_foo` + --> $DIR/fn-trait-cast-diagnostic.rs:18:29 + | +LL | fn do_on_single_foo(v: impl NoOtherFoo) {} + | ^^^^^^^^^^ required by this bound in `do_on_single_foo` +help: the trait `NoOtherFoo` is implemented for fn pointer `fn() -> bool`, try casting using `as` + | +LL | do_on_single_foo(example as fn() -> bool); + | +++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr index 4fe12731475b4..6b5b721384cbb 100644 --- a/tests/ui/traits/issue-43784-supertrait.stderr +++ b/tests/ui/traits/issue-43784-supertrait.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | impl Complete for T {} | ^ the trait `Copy` is not implemented for `T` | +note: required for `T` to implement `Partial` + --> $DIR/issue-43784-supertrait.rs:1:11 + | +LL | pub trait Partial: Copy { + | ^^^^^^^ note: required by a bound in `Complete` --> $DIR/issue-43784-supertrait.rs:4:21 | diff --git a/tests/ui/traits/issue-52893.stderr b/tests/ui/traits/issue-52893.stderr index 7924d3db06f36..a11867c03a689 100644 --- a/tests/ui/traits/issue-52893.stderr +++ b/tests/ui/traits/issue-52893.stderr @@ -11,6 +11,13 @@ LL | builder.push(output); | = note: expected type parameter `F` found struct `Class

` +help: the return type of this call is `Class

` due to the type of the argument passed + --> $DIR/issue-52893.rs:53:9 + | +LL | builder.push(output); + | ^^^^^^^^^^^^^------^ + | | + | this argument influences the return type of `push` note: associated function defined here --> $DIR/issue-52893.rs:11:8 | diff --git a/tests/ui/traits/issue-99875.stderr b/tests/ui/traits/issue-99875.stderr index 3ff8f12f1b8ce..fb6eebbd254a2 100644 --- a/tests/ui/traits/issue-99875.stderr +++ b/tests/ui/traits/issue-99875.stderr @@ -6,12 +6,15 @@ LL | takes(function); | | | required by a bound introduced by this call | - = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return` note: required by a bound in `takes` --> $DIR/issue-99875.rs:9:18 | LL | fn takes(_: impl Trait) {} | ^^^^^ required by this bound in `takes` +help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, try casting using `as` + | +LL | takes(function as fn(Argument) -> Return); + | +++++++++++++++++++++++++ error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied --> $DIR/issue-99875.rs:14:11 diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs new file mode 100644 index 0000000000000..77e753c13f739 --- /dev/null +++ b/tests/ui/traits/track-obligations.rs @@ -0,0 +1,88 @@ +// These are simplifications of the tower traits by the same name: + +pub trait Service { + type Response; +} + +pub trait Layer { + type Service; +} + +// Any type will do here: + +pub struct Req; +pub struct Res; + +// This is encoding a trait alias. + +pub trait ParticularService: + Service { +} + +impl ParticularService for T +where + T: Service, +{ +} + +// This is also a trait alias. +// The weird = bound is there so that users of the trait do not +// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671 +// for context, and in particular the workaround in: +// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828 + +pub trait ParticularServiceLayer: + Layer>::Service> +{ + type Service: ParticularService; +} + +impl ParticularServiceLayer for T +where + T: Layer, + T::Service: ParticularService, +{ + type Service = T::Service; +} + +// These are types that implement the traits that the trait aliases refer to. +// They should also implement the alias traits due to the blanket impls. + +struct ALayer(C); +impl Layer for ALayer { + type Service = AService; +} + +struct AService; +impl Service for AService { + // However, AService does _not_ meet the blanket implementation, + // since its Response type is bool, not Res as it should be. + type Response = bool; +} + +// This is a wrapper type around ALayer that uses the trait alias +// as a way to communicate the requirements of the provided types. +struct Client(C); + +// The method and the free-standing function below both have the same bounds. + +impl Client +where + ALayer: ParticularServiceLayer, +{ + fn check(&self) {} +} + +fn check(_: C) where ALayer: ParticularServiceLayer {} + +// But, they give very different error messages. + +fn main() { + // This gives a very poor error message that does nothing to point the user + // at the underlying cause of why the types involved do not meet the bounds. + Client(()).check(); //~ ERROR E0599 + + // This gives a good(ish) error message that points the user at _why_ the + // bound isn't met, and thus how they might fix it. + check(()); //~ ERROR E0271 +} diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr new file mode 100644 index 0000000000000..89477475970f4 --- /dev/null +++ b/tests/ui/traits/track-obligations.stderr @@ -0,0 +1,76 @@ +error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied + --> $DIR/track-obligations.rs:83:16 + | +LL | struct ALayer(C); + | ---------------- + | | + | doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` + | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` +... +LL | struct Client(C); + | ---------------- method `check` not found for this struct +... +LL | Client(()).check(); + | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds + | +note: trait bound ` as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` was not satisfied + --> $DIR/track-obligations.rs:35:14 + | +LL | pub trait ParticularServiceLayer: + | ---------------------- +LL | Layer>::Service> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied + --> $DIR/track-obligations.rs:71:16 + | +LL | impl Client + | --------- +LL | where +LL | ALayer: ParticularServiceLayer, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: the trait `ParticularServiceLayer` must be implemented + --> $DIR/track-obligations.rs:34:1 + | +LL | / pub trait ParticularServiceLayer: +LL | | Layer>::Service> + | |____________________________________________________________________^ + +error[E0271]: type mismatch resolving `>::Response == Res` + --> $DIR/track-obligations.rs:87:11 + | +LL | check(()); + | ----- ^^ type mismatch resolving `>::Response == Res` + | | + | required by a bound introduced by this call + | +note: expected this to be `Res` + --> $DIR/track-obligations.rs:60:21 + | +LL | type Response = bool; + | ^^^^ +note: required for `AService` to implement `ParticularService` + --> $DIR/track-obligations.rs:22:9 + | +LL | impl ParticularService for T + | ^^^^^^^^^^^^^^^^^ ^ +LL | where +LL | T: Service, + | -------------- unsatisfied trait bound introduced here +note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>` + --> $DIR/track-obligations.rs:40:12 + | +LL | impl ParticularServiceLayer for T + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T::Service: ParticularService, + | ----------------- unsatisfied trait bound introduced here +note: required by a bound in `check` + --> $DIR/track-obligations.rs:76:36 + | +LL | fn check(_: C) where ALayer: ParticularServiceLayer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0599. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs new file mode 100644 index 0000000000000..ba5b9f54246e2 --- /dev/null +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs @@ -0,0 +1,28 @@ +fn function(x: T, y: bool) -> T { + x +} + +struct S {} +impl S { + fn method(&self, x: T) -> T { + x + } +} + +fn wrong_arg_type(x: u32) -> u32 { + x +} + +fn main() { + // Should not trigger. + let x = wrong_arg_type(0u16); //~ ERROR mismatched types + let x: u16 = function(0, 0u8); //~ ERROR mismatched types + + // Should trigger exactly once for the first argument. + let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect + + // Should trigger. + let x: u16 = function(0u32, true); //~ ERROR mismatched types + let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types + function(0u32, 8u8) //~ ERROR arguments to this function are incorrect +} diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr new file mode 100644 index 0000000000000..4d012cb156bb5 --- /dev/null +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -0,0 +1,131 @@ +error[E0308]: mismatched types + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28 + | +LL | let x = wrong_arg_type(0u16); + | -------------- ^^^^ expected `u32`, found `u16` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4 + | +LL | fn wrong_arg_type(x: u32) -> u32 { + | ^^^^^^^^^^^^^^ ------ +help: change the type of the numeric literal from `u16` to `u32` + | +LL | let x = wrong_arg_type(0u32); + | ~~~ + +error[E0308]: mismatched types + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30 + | +LL | let x: u16 = function(0, 0u8); + | -------- ^^^ expected `bool`, found `u8` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 + | +LL | fn function(x: T, y: bool) -> T { + | ^^^^^^^^ ------- + +error[E0308]: arguments to this function are incorrect + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18 + | +LL | let x: u16 = function(0u32, 0u8); + | ^^^^^^^^ ---- --- expected `bool`, found `u8` + | | + | expected `u16`, found `u32` + | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18 + | +LL | let x: u16 = function(0u32, 0u8); + | ^^^^^^^^^----^^^^^^ + | | + | this argument influences the return type of `function` +note: function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 + | +LL | fn function(x: T, y: bool) -> T { + | ^^^^^^^^ ---- ------- +help: change the type of the numeric literal from `u32` to `u16` + | +LL | let x: u16 = function(0u16, 0u8); + | ~~~ + +error[E0308]: mismatched types + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27 + | +LL | let x: u16 = function(0u32, true); + | -------- ^^^^ expected `u16`, found `u32` + | | + | arguments to this function are incorrect + | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18 + | +LL | let x: u16 = function(0u32, true); + | ^^^^^^^^^----^^^^^^^ + | | + | this argument influences the return type of `function` +note: function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 + | +LL | fn function(x: T, y: bool) -> T { + | ^^^^^^^^ ---- +help: change the type of the numeric literal from `u32` to `u16` + | +LL | let x: u16 = function(0u16, true); + | ~~~ + +error[E0308]: mismatched types + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32 + | +LL | let x: u16 = (S {}).method(0u32); + | ------ ^^^^ expected `u16`, found `u32` + | | + | arguments to this method are incorrect + | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18 + | +LL | let x: u16 = (S {}).method(0u32); + | ^^^^^^^^^^^^^^----^ + | | + | this argument influences the return type of `method` +note: associated function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8 + | +LL | fn method(&self, x: T) -> T { + | ^^^^^^ ---- +help: change the type of the numeric literal from `u32` to `u16` + | +LL | let x: u16 = (S {}).method(0u16); + | ~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5 + | +LL | function(0u32, 8u8) + | ^^^^^^^^ ---- --- expected `bool`, found `u8` + | | + | expected `()`, found `u32` + | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5 + | +LL | function(0u32, 8u8) + | ^^^^^^^^^----^^^^^^ + | | + | this argument influences the return type of `function` +note: function defined here + --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 + | +LL | fn function(x: T, y: bool) -> T { + | ^^^^^^^^ ---- ------- + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-46112.stderr b/tests/ui/typeck/issue-46112.stderr index f488463ae3ce9..8f5ff51fbe100 100644 --- a/tests/ui/typeck/issue-46112.stderr +++ b/tests/ui/typeck/issue-46112.stderr @@ -8,6 +8,13 @@ LL | fn main() { test(Ok(())); } | = note: expected enum `Option<()>` found unit type `()` +help: the type constructed contains `()` due to the type of the argument passed + --> $DIR/issue-46112.rs:9:18 + | +LL | fn main() { test(Ok(())); } + | ^^^--^ + | | + | this argument influences the type of `Ok` note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL help: try wrapping the expression in `Some` diff --git a/tests/ui/typeck/issue-84768.stderr b/tests/ui/typeck/issue-84768.stderr index 00d23389720b9..09f3aee2d9ec5 100644 --- a/tests/ui/typeck/issue-84768.stderr +++ b/tests/ui/typeck/issue-84768.stderr @@ -14,6 +14,13 @@ LL | ::call_once(f, 1) | = note: expected tuple `(&mut u8,)` found type `{integer}` +help: the return type of this call is `{integer}` due to the type of the argument passed + --> $DIR/issue-84768.rs:7:5 + | +LL | ::call_once(f, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ + | | + | this argument influences the return type of `FnOnce` note: associated function defined here --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index a2fe627868aeb..e85144a31ca96 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -21,6 +21,13 @@ LL | >::add(1u32, 2); | | | arguments to this function are incorrect | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/ufcs-qpath-self-mismatch.rs:7:5 + | +LL | >::add(1u32, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^----^^^^ + | | + | this argument influences the return type of `Add` note: associated function defined here --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the type of the numeric literal from `u32` to `i32` @@ -36,6 +43,13 @@ LL | >::add(1, 2u32); | | | arguments to this function are incorrect | +help: the return type of this call is `u32` due to the type of the argument passed + --> $DIR/ufcs-qpath-self-mismatch.rs:9:5 + | +LL | >::add(1, 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^ + | | + | this argument influences the return type of `Add` note: associated function defined here --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the type of the numeric literal from `u32` to `i32` diff --git a/triagebot.toml b/triagebot.toml index 914b52cf041db..14bade6472fa6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -251,7 +251,7 @@ new_pr = true [autolabel."WG-trait-system-refactor"] trigger_files = [ - "compiler/rustc_trait_selection/solve" + "compiler/rustc_trait_selection/src/solve" ] [notify-zulip."I-prioritize"]