Skip to content

Commit b9de4ef

Browse files
committed
Auto merge of #64127 - Centril:rollup-dfgb9h8, r=Centril
Rollup of 5 pull requests Successful merges: - #64049 (Emit a single error on if expr with expectation and no else clause) - #64056 (Account for arbitrary self types in E0599) - #64058 (librustc_errors: Extract sugg/subst handling into method) - #64071 (use just one name when parameters and fields are the same) - #64104 (Emit error on intrinsic to fn ptr casts) Failed merges: r? @ghost
2 parents 815dec9 + 24e3b1d commit b9de4ef

26 files changed

+269
-145
lines changed

src/librustc/infer/error_reporting/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,9 @@ impl<'tcx> ObligationCause<'tcx> {
16361636
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
16371637
Error0644("closure/generator type that references itself")
16381638
}
1639+
TypeError::IntrinsicCast => {
1640+
Error0308("cannot coerce intrinsics to function pointers")
1641+
}
16391642
_ => Error0308("mismatched types"),
16401643
},
16411644
}

src/librustc/ty/context.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,12 @@ impl<'tcx> TyCtxt<'tcx> {
24022402
self.mk_generic_adt(def_id, ty)
24032403
}
24042404

2405+
#[inline]
2406+
pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> {
2407+
let def_id = self.require_lang_item(item, None);
2408+
self.mk_generic_adt(def_id, ty)
2409+
}
2410+
24052411
#[inline]
24062412
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
24072413
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);

src/librustc/ty/error.rs

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub enum TypeError<'tcx> {
4646
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
4747

4848
ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
49+
50+
IntrinsicCast,
4951
}
5052

5153
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -179,6 +181,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
179181
ConstMismatch(ref values) => {
180182
write!(f, "expected `{}`, found `{}`", values.expected, values.found)
181183
}
184+
IntrinsicCast => {
185+
write!(f, "cannot coerce intrinsics to function pointers")
186+
}
182187
}
183188
}
184189
}

src/librustc/ty/structural_impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
748748
Sorts(ref x) => return tcx.lift(x).map(Sorts),
749749
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
750750
ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
751+
IntrinsicCast => IntrinsicCast,
751752
})
752753
}
753754
}
@@ -1338,6 +1339,7 @@ EnumTypeFoldableImpl! {
13381339
(ty::error::TypeError::Sorts)(x),
13391340
(ty::error::TypeError::ExistentialMismatch)(x),
13401341
(ty::error::TypeError::ConstMismatch)(x),
1342+
(ty::error::TypeError::IntrinsicCast),
13411343
}
13421344
}
13431345

src/librustc_errors/annotate_snippet_emitter_writer.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ pub struct AnnotateSnippetEmitterWriter {
3030
impl Emitter for AnnotateSnippetEmitterWriter {
3131
/// The entry point for the diagnostics generation
3232
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
33-
let primary_span = db.span.clone();
3433
let children = db.children.clone();
35-
// FIXME(#59346): Collect suggestions (see emitter.rs)
36-
let suggestions: &[_] = &[];
34+
let (primary_span, suggestions) = self.primary_span_formatted(&db);
3735

3836
// FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs
3937

src/librustc_errors/emitter.rs

+31-9
Original file line numberDiff line numberDiff line change
@@ -191,16 +191,25 @@ pub trait Emitter {
191191
fn should_show_explain(&self) -> bool {
192192
true
193193
}
194-
}
195194

196-
impl Emitter for EmitterWriter {
197-
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
195+
/// Formats the substitutions of the primary_span
196+
///
197+
/// The are a lot of conditions to this method, but in short:
198+
///
199+
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
200+
/// we format the `help` suggestion depending on the content of the
201+
/// substitutions. In that case, we return the modified span only.
202+
///
203+
/// * If the current `Diagnostic` has multiple suggestions,
204+
/// we return the original `primary_span` and the original suggestions.
205+
fn primary_span_formatted<'a>(
206+
&mut self,
207+
db: &'a DiagnosticBuilder<'_>
208+
) -> (MultiSpan, &'a [CodeSuggestion]) {
198209
let mut primary_span = db.span.clone();
199-
let mut children = db.children.clone();
200-
let mut suggestions: &[_] = &[];
201-
202210
if let Some((sugg, rest)) = db.suggestions.split_first() {
203211
if rest.is_empty() &&
212+
// ^ if there is only one suggestion
204213
// don't display multi-suggestions as labels
205214
sugg.substitutions.len() == 1 &&
206215
// don't display multipart suggestions as labels
@@ -216,21 +225,34 @@ impl Emitter for EmitterWriter {
216225
{
217226
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
218227
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
219-
// This substitution is only removal or we explicitly don't want to show the
220-
// code inline, don't show it
228+
// This substitution is only removal OR we explicitly don't want to show the
229+
// code inline (`hide_inline`). Therefore, we don't show the substitution.
221230
format!("help: {}", sugg.msg)
222231
} else {
232+
// Show the default suggestion text with the substitution
223233
format!("help: {}: `{}`", sugg.msg, substitution)
224234
};
225235
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
236+
237+
// We return only the modified primary_span
238+
(primary_span, &[])
226239
} else {
227240
// if there are multiple suggestions, print them all in full
228241
// to be consistent. We could try to figure out if we can
229242
// make one (or the first one) inline, but that would give
230243
// undue importance to a semi-random suggestion
231-
suggestions = &db.suggestions;
244+
(primary_span, &db.suggestions)
232245
}
246+
} else {
247+
(primary_span, &db.suggestions)
233248
}
249+
}
250+
}
251+
252+
impl Emitter for EmitterWriter {
253+
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
254+
let mut children = db.children.clone();
255+
let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
234256

235257
self.fix_multispans_in_std_macros(&mut primary_span,
236258
&mut children,

src/librustc_typeck/check/_match.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
112112
}
113113

114114
self.diverges.set(pats_diverge);
115-
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
115+
let arm_ty = if source_if && if_no_else && i != 0 && self.if_fallback_coercion(
116+
expr.span,
117+
&arms[0].body,
118+
&mut coercion,
119+
) {
120+
tcx.types.err
121+
} else {
122+
// Only call this if this is not an `if` expr with an expected type and no `else`
123+
// clause to avoid duplicated type errors. (#60254)
124+
self.check_expr_with_expectation(&arm.body, expected)
125+
};
116126
all_arms_diverge &= self.diverges.get();
117-
118-
let span = expr.span;
119-
120127
if source_if {
121128
let then_expr = &arms[0].body;
122129
match (i, if_no_else) {
123-
(0, _) => coercion.coerce(self, &self.misc(span), &arm.body, arm_ty),
124-
(_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion),
130+
(0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty),
131+
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
125132
(_, _) => {
126133
let then_ty = prior_arm_ty.unwrap();
127-
let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty);
134+
let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty);
128135
coercion.coerce(self, &cause, &arm.body, arm_ty);
129136
}
130137
}
@@ -139,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
139146
// The reason for the first arm to fail is not that the match arms diverge,
140147
// but rather that there's a prior obligation that doesn't hold.
141148
0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
142-
_ => (span, ObligationCauseCode::MatchExpressionArm {
149+
_ => (expr.span, ObligationCauseCode::MatchExpressionArm {
143150
arm_span,
144151
source: match_src,
145152
prior_arms: other_arms.clone(),
@@ -180,16 +187,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
180187
}
181188

182189
/// Handle the fallback arm of a desugared if(-let) like a missing else.
190+
///
191+
/// Returns `true` if there was an error forcing the coercion to the `()` type.
183192
fn if_fallback_coercion(
184193
&self,
185194
span: Span,
186195
then_expr: &'tcx hir::Expr,
187196
coercion: &mut CoerceMany<'tcx, '_, rustc::hir::Arm>,
188-
) {
197+
) -> bool {
189198
// If this `if` expr is the parent's function return expr,
190199
// the cause of the type coercion is the return type, point at it. (#25228)
191200
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
192201
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
202+
let mut error = false;
193203
coercion.coerce_forced_unit(self, &cause, &mut |err| {
194204
if let Some((span, msg)) = &ret_reason {
195205
err.span_label(*span, msg.as_str());
@@ -200,7 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200210
}
201211
err.note("`if` expressions without `else` evaluate to `()`");
202212
err.help("consider adding an `else` block that evaluates to the expected type");
213+
error = true;
203214
}, ret_reason.is_none());
215+
error
204216
}
205217

206218
fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {

src/librustc_typeck/check/cast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use rustc::ty::{self, Ty, TypeFoldable, TypeAndMut};
4040
use rustc::ty::subst::SubstsRef;
4141
use rustc::ty::adjustment::AllowTwoPhase;
4242
use rustc::ty::cast::{CastKind, CastTy};
43+
use rustc::ty::error::TypeError;
4344
use rustc::middle::lang_items;
4445
use syntax::ast;
4546
use syntax_pos::Span;
@@ -461,6 +462,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
461462
self.expr_ty,
462463
fcx.tcx.mk_fn_ptr(f),
463464
AllowTwoPhase::No);
465+
if let Err(TypeError::IntrinsicCast) = res {
466+
return Err(CastError::IllegalCast);
467+
}
464468
if res.is_err() {
465469
return Err(CastError::NonScalar);
466470
}

src/librustc_typeck/check/coercion.rs

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use std::ops::Deref;
7070
use syntax::feature_gate;
7171
use syntax::symbol::sym;
7272
use syntax_pos;
73+
use rustc_target::spec::abi::Abi;
7374

7475
struct Coerce<'a, 'tcx> {
7576
fcx: &'a FnCtxt<'a, 'tcx>,
@@ -689,6 +690,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
689690
match b.sty {
690691
ty::FnPtr(_) => {
691692
let a_sig = a.fn_sig(self.tcx);
693+
// Intrinsics are not coercible to function pointers
694+
if a_sig.abi() == Abi::RustIntrinsic ||
695+
a_sig.abi() == Abi::PlatformIntrinsic {
696+
return Err(TypeError::IntrinsicCast);
697+
}
692698
let InferOk { value: a_sig, mut obligations } =
693699
self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);
694700

src/librustc_typeck/check/expr.rs

+68-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::check::fatally_break_rust;
1212
use crate::check::report_unexpected_variant_res;
1313
use crate::check::Needs;
1414
use crate::check::TupleArgumentsFlag::DontTupleArguments;
15-
use crate::check::method::SelfSource;
15+
use crate::check::method::{probe, SelfSource, MethodError};
1616
use crate::util::common::ErrorReported;
1717
use crate::util::nodemap::FxHashMap;
1818
use crate::astconv::AstConv as _;
@@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind};
2929
use rustc::hir::ptr::P;
3030
use rustc::infer;
3131
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
32+
use rustc::middle::lang_items;
3233
use rustc::mir::interpret::GlobalId;
3334
use rustc::ty;
3435
use rustc::ty::adjustment::{
@@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
775776
// no need to check for bot/err -- callee does that
776777
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
777778

778-
let method = match self.lookup_method(rcvr_t,
779-
segment,
780-
span,
781-
expr,
782-
rcvr) {
779+
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
783780
Ok(method) => {
784781
self.write_method_call(expr.hir_id, method);
785782
Ok(method)
786783
}
787784
Err(error) => {
788785
if segment.ident.name != kw::Invalid {
789-
self.report_method_error(span,
790-
rcvr_t,
791-
segment.ident,
792-
SelfSource::MethodCall(rcvr),
793-
error,
794-
Some(args));
786+
self.report_extended_method_error(segment, span, args, rcvr_t, error);
795787
}
796788
Err(())
797789
}
798790
};
799791

800792
// Call the generic checker.
801-
self.check_method_argument_types(span,
802-
expr.span,
803-
method,
804-
&args[1..],
805-
DontTupleArguments,
806-
expected)
793+
self.check_method_argument_types(
794+
span,
795+
expr.span,
796+
method,
797+
&args[1..],
798+
DontTupleArguments,
799+
expected,
800+
)
801+
}
802+
803+
fn report_extended_method_error(
804+
&self,
805+
segment: &hir::PathSegment,
806+
span: Span,
807+
args: &'tcx [hir::Expr],
808+
rcvr_t: Ty<'tcx>,
809+
error: MethodError<'tcx>
810+
) {
811+
let rcvr = &args[0];
812+
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
813+
if let Ok(pick) = self.lookup_probe(
814+
span,
815+
segment.ident,
816+
new_rcvr_t,
817+
rcvr,
818+
probe::ProbeScope::AllTraits,
819+
) {
820+
err.span_label(
821+
pick.item.ident.span,
822+
&format!("the method is available for `{}` here", new_rcvr_t),
823+
);
824+
}
825+
};
826+
827+
if let Some(mut err) = self.report_method_error(
828+
span,
829+
rcvr_t,
830+
segment.ident,
831+
SelfSource::MethodCall(rcvr),
832+
error,
833+
Some(args),
834+
) {
835+
if let ty::Adt(..) = rcvr_t.sty {
836+
// Try alternative arbitrary self types that could fulfill this call.
837+
// FIXME: probe for all types that *could* be arbitrary self-types, not
838+
// just this whitelist.
839+
let box_rcvr_t = self.tcx.mk_box(rcvr_t);
840+
try_alt_rcvr(&mut err, box_rcvr_t);
841+
let pin_rcvr_t = self.tcx.mk_lang_item(
842+
rcvr_t,
843+
lang_items::PinTypeLangItem,
844+
);
845+
try_alt_rcvr(&mut err, pin_rcvr_t);
846+
let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
847+
try_alt_rcvr(&mut err, arc_rcvr_t);
848+
let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
849+
try_alt_rcvr(&mut err, rc_rcvr_t);
850+
}
851+
err.emit();
852+
}
807853
}
808854

809855
fn check_expr_cast(
@@ -1466,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14661512
let struct_variant_def = def.non_enum_variant();
14671513
let field_names = self.available_field_names(struct_variant_def);
14681514
if !field_names.is_empty() {
1469-
err.note(&format!("available fields are: {}",
1470-
self.name_series_display(field_names)));
1515+
err.note(&format!(
1516+
"available fields are: {}",
1517+
self.name_series_display(field_names),
1518+
));
14711519
}
14721520
}
14731521
}

src/librustc_typeck/check/method/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
245245
Ok(result.callee)
246246
}
247247

248-
fn lookup_probe(
248+
pub fn lookup_probe(
249249
&self,
250250
span: Span,
251251
method_name: ast::Ident,

0 commit comments

Comments
 (0)