Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3954,6 +3954,7 @@ dependencies = [
"rustc_errors",
"rustc_expand",
"rustc_feature",
"rustc_hir",
"rustc_hir_analysis",
"rustc_hir_pretty",
"rustc_index",
Expand Down Expand Up @@ -4414,7 +4415,6 @@ dependencies = [
"rustc_graphviz",
"rustc_hashes",
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
"rustc_lint_defs",
"rustc_macros",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_driver_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_index = { path = "../rustc_index" }
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_driver_impl/src/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use std::io;

use rustc_ast as ast;
use rustc_ast_pretty::pprust as pprust_ast;
use rustc_hir::intravisit;
use rustc_hir_pretty as pprust_hir;
use rustc_hir_pretty::PpAnn;
use rustc_middle::bug;
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
use rustc_middle::ty::{self, TyCtxt};
Expand Down Expand Up @@ -71,7 +73,8 @@ struct HirIdentifiedAnn<'tcx> {

impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
self.tcx.nested(state, nested)
let this = &self.tcx as &dyn intravisit::HirTyCtxt<'_>;
this.nested(state, nested)
}

fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
Expand Down Expand Up @@ -149,11 +152,12 @@ struct HirTypedAnn<'tcx> {

impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
let this = &self.tcx as &dyn intravisit::HirTyCtxt<'_>;
let old_maybe_typeck_results = self.maybe_typeck_results.get();
if let pprust_hir::Nested::Body(id) = nested {
self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id)));
}
self.tcx.nested(state, nested);
this.nested(state, nested);
self.maybe_typeck_results.set(old_maybe_typeck_results);
}

Expand Down Expand Up @@ -281,7 +285,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
)
};
match s {
PpHirMode::Normal => f(&tcx),
PpHirMode::Normal => f(&(&tcx as &dyn intravisit::HirTyCtxt<'_>) as &dyn PpAnn),
PpHirMode::Identified => {
let annotation = HirIdentifiedAnn { tcx };
f(&annotation)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return self.get_fn_decl(hir_id).map(|(_, fn_decl)| {
let (ty, span) = match fn_decl.output {
hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span),
hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span),
hir::FnRetTy::Return(ty) => (ty_to_string(self, ty), ty.span),
};
(span, format!("expected `{ty}` because of this return type"))
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let removal_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
unit_variant =
Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(&self.tcx, qpath)));
Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(self, qpath)));
}

let callee_ty = self.resolve_vars_if_possible(callee_ty);
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use crate::diagnostics::{
use crate::op::contains_let_in_chain;
use crate::{
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,
TupleArgumentsFlag, cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct,
TupleArgumentsFlag, cast, fatally_break_rust, type_error_struct,
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Expand Down Expand Up @@ -589,8 +589,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ty::new_error(tcx, e)
}
Res::Def(DefKind::Variant, _) => {
let e = report_unexpected_variant_res(
tcx,
let e = self.report_unexpected_variant_res(
res,
Some(expr),
&[],
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
}
}

impl<'tcx> rustc_hir_pretty::PpAnn for FnCtxt<'_, 'tcx> {
fn nested(&self, state: &mut rustc_hir_pretty::State<'_>, nested: rustc_hir_pretty::Nested) {
rustc_hir_pretty::PpAnn::nested(
&(&self.tcx as &dyn rustc_hir::intravisit::HirTyCtxt<'_>),
state,
nested,
)
}
}

impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::FnDecl { inputs, output, .. } = fn_ptr_ty.decl;

let inputs_str =
inputs.iter().map(|ty| rustc_hir_pretty::ty_to_string(&self.tcx, ty)).join(", ");
inputs.iter().map(|ty| rustc_hir_pretty::ty_to_string(self, ty)).join(", ");

let output_str = match output {
hir::FnRetTy::DefaultReturn(_) => String::new(),
hir::FnRetTy::Return(ty) => {
format!(" -> {}", rustc_hir_pretty::ty_to_string(&self.tcx, ty))
format!(" -> {}", rustc_hir_pretty::ty_to_string(self, ty))
}
};

Expand Down
244 changes: 124 additions & 120 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,134 +478,138 @@ impl<'tcx> EnclosingBreakables<'tcx> {
}
}
}

fn report_unexpected_variant_res(
tcx: TyCtxt<'_>,
res: Res,
expr: Option<&hir::Expr<'_>>,
sub_pats: &[hir::Pat<'_>],
qpath: &hir::QPath<'_>,
span: Span,
err_code: ErrCode,
expected: &str,
) -> ErrorGuaranteed {
let res_descr = match res {
Res::Def(DefKind::Variant, _) => "struct variant",
_ => res.descr(),
};
let path_str = rustc_hir_pretty::qpath_to_string(&tcx, qpath);
let mut err = tcx
.dcx()
.struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`"))
.with_code(err_code);
match res {
Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == E0164 => {
let patterns_url = "https://doc.rust-lang.org/book/ch19-00-patterns.html";
err.with_span_label(span, "`fn` calls are not allowed in patterns")
.with_help(format!("for more information, visit {patterns_url}"))
}
Res::Def(DefKind::Variant, _) if let Some(expr) = expr => {
err.span_label(span, format!("not a {expected}"));
let variant = tcx.expect_variant_res(res);
let sugg = if variant.fields.is_empty() {
" {}".to_string()
} else {
format!(
" {{ {} }}",
variant
.fields
.iter()
.map(|f| format!("{}: /* value */", f.name))
.collect::<Vec<_>>()
.join(", ")
)
};
let descr = "you might have meant to create a new value of the struct";
let mut suggestion = vec![];
match tcx.parent_hir_node(expr.hir_id) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Call(..),
span: call_span,
..
}) => {
suggestion.push((span.shrink_to_hi().with_hi(call_span.hi()), sugg));
}
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(..), hir_id, .. }) => {
suggestion.push((expr.span.shrink_to_lo(), "(".to_string()));
if let hir::Node::Expr(parent) = tcx.parent_hir_node(*hir_id)
&& let hir::ExprKind::If(condition, block, None) = parent.kind
&& condition.hir_id == *hir_id
&& let hir::ExprKind::Block(block, _) = block.kind
&& block.stmts.is_empty()
&& let Some(expr) = block.expr
&& let hir::ExprKind::Path(..) = expr.kind
{
// Special case: you can incorrectly write an equality condition:
// if foo == Struct { field } { /* if body */ }
// which should have been written
// if foo == (Struct { field }) { /* if body */ }
suggestion.push((block.span.shrink_to_hi(), ")".to_string()));
} else {
suggestion.push((span.shrink_to_hi().with_hi(expr.span.hi()), sugg));
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn report_unexpected_variant_res(
&self,
res: Res,
expr: Option<&hir::Expr<'_>>,
sub_pats: &[hir::Pat<'_>],
qpath: &hir::QPath<'_>,
span: Span,
err_code: ErrCode,
expected: &str,
) -> ErrorGuaranteed {
let tcx = self.tcx;
let res_descr = match res {
Res::Def(DefKind::Variant, _) => "struct variant",
_ => res.descr(),
};
let path_str = rustc_hir_pretty::qpath_to_string(self, qpath);
let mut err = tcx
.dcx()
.struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`"))
.with_code(err_code);
match res {
Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == E0164 => {
let patterns_url = "https://doc.rust-lang.org/book/ch19-00-patterns.html";
err.with_span_label(span, "`fn` calls are not allowed in patterns")
.with_help(format!("for more information, visit {patterns_url}"))
}
Res::Def(DefKind::Variant, _) if let Some(expr) = expr => {
err.span_label(span, format!("not a {expected}"));
let variant = tcx.expect_variant_res(res);
let sugg = if variant.fields.is_empty() {
" {}".to_string()
} else {
format!(
" {{ {} }}",
variant
.fields
.iter()
.map(|f| format!("{}: /* value */", f.name))
.collect::<Vec<_>>()
.join(", ")
)
};
let descr = "you might have meant to create a new value of the struct";
let mut suggestion = vec![];
match tcx.parent_hir_node(expr.hir_id) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Call(..),
span: call_span,
..
}) => {
suggestion.push((span.shrink_to_hi().with_hi(call_span.hi()), sugg));
}
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Binary(..), hir_id, ..
}) => {
suggestion.push((expr.span.shrink_to_lo(), "(".to_string()));
if let hir::Node::Expr(parent) = tcx.parent_hir_node(*hir_id)
&& let hir::ExprKind::If(condition, block, None) = parent.kind
&& condition.hir_id == *hir_id
&& let hir::ExprKind::Block(block, _) = block.kind
&& block.stmts.is_empty()
&& let Some(expr) = block.expr
&& let hir::ExprKind::Path(..) = expr.kind
{
// Special case: you can incorrectly write an equality condition:
// if foo == Struct { field } { /* if body */ }
// which should have been written
// if foo == (Struct { field }) { /* if body */ }
suggestion.push((block.span.shrink_to_hi(), ")".to_string()));
} else {
suggestion.push((span.shrink_to_hi().with_hi(expr.span.hi()), sugg));
}
}
_ => {
suggestion.push((span.shrink_to_hi(), sugg));
}
}
_ => {
suggestion.push((span.shrink_to_hi(), sugg));
}

err.multipart_suggestion(descr, suggestion, Applicability::HasPlaceholders);
err
}
Res::Def(DefKind::Variant, _) if expr.is_none() => {
err.span_label(span, format!("not a {expected}"));

err.multipart_suggestion(descr, suggestion, Applicability::HasPlaceholders);
err
}
Res::Def(DefKind::Variant, _) if expr.is_none() => {
err.span_label(span, format!("not a {expected}"));

let fields = &tcx.expect_variant_res(res).fields.raw;
let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi());
let (msg, sugg) = if fields.is_empty() {
("use the struct variant pattern syntax", " {}".to_string())
} else {
let msg = if fields.is_empty() {
"use struct variant pattern syntax"
let fields = &tcx.expect_variant_res(res).fields.raw;
let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi());
let (msg, sugg) = if fields.is_empty() {
("use the struct variant pattern syntax", " {}".to_string())
} else {
"add the names to match a struct variant's fields"
let msg = if fields.is_empty() {
"use struct variant pattern syntax"
} else {
"add the names to match a struct variant's fields"
};
let fields_sugg = fields
.iter()
.enumerate()
.map(|(i, field)| {
let field_name = field.ident(tcx).to_string();

let pat_snippet = sub_pats
.get(i)
.and_then(|sub_pat| {
tcx.sess.source_map().span_to_snippet(sub_pat.span).ok()
})
.unwrap_or_else(|| "_".to_string());

if field_name == pat_snippet {
field_name
} else {
format!("{field_name}: {pat_snippet}")
}
})
.collect::<Vec<_>>()
.join(", ");
let sugg = format!(" {{ {} }}", fields_sugg);
(msg, sugg)
};
let fields_sugg = fields
.iter()
.enumerate()
.map(|(i, field)| {
let field_name = field.ident(tcx).to_string();

let pat_snippet = sub_pats
.get(i)
.and_then(|sub_pat| {
tcx.sess.source_map().span_to_snippet(sub_pat.span).ok()
})
.unwrap_or_else(|| "_".to_string());

if field_name == pat_snippet {
field_name
} else {
format!("{field_name}: {pat_snippet}")
}
})
.collect::<Vec<_>>()
.join(", ");
let sugg = format!(" {{ {} }}", fields_sugg);
(msg, sugg)
};

err.span_suggestion_verbose(
qpath.span().shrink_to_hi().to(span.shrink_to_hi()),
msg,
sugg,
Applicability::HasPlaceholders,
);
err

err.span_suggestion_verbose(
qpath.span().shrink_to_hi().to(span.shrink_to_hi()),
msg,
sugg,
Applicability::HasPlaceholders,
);
err
}
_ => err.with_span_label(span, format!("not a {expected}")),
}
_ => err.with_span_label(span, format!("not a {expected}")),
.emit()
}
.emit()
}

/// Controls whether all arguments are tupled. This is used for the call operator only.
Expand Down
Loading
Loading