Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #78371

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
57d01a9
Check which places are dead
simonvandel Oct 22, 2020
d0d0e78
Capture output from threads spawned in tests
tmandry Aug 5, 2020
db15596
Only load LOCAL_STREAMS if they are being used
SergioBenitez Oct 22, 2020
86df903
Tweak "use `.await`" suggestion
estebank Oct 21, 2020
a4ee3ca
Suggest semicolon removal on prior match arm
estebank Oct 22, 2020
671d7c4
Account for possible boxable `impl Future` in semicolon removal sugge…
estebank Oct 22, 2020
62ba365
Review comments: use newtype instead of `bool`
estebank Oct 22, 2020
3a0227b
Silence unnecessary `await foo?` knock-down error
estebank Oct 22, 2020
1829b4a
Add test case for different `impl Future`s
estebank Oct 22, 2020
c548511
Add more `.await` suggestions on E0308
estebank Oct 23, 2020
f5d7443
Suggest semicolon removal and boxing when appropriate
estebank Oct 23, 2020
1333206
ensure that statics are inhabited
RalfJung Oct 24, 2020
2585124
Miri engine validity check: simplify code with 'matches!'
RalfJung Oct 21, 2020
d8ec83f
Miri engine interning: improve comments, and entirely skip ZST
RalfJung Oct 21, 2020
778ddff
ensure we intern all promoteds as InternKind::Promoted
RalfJung Oct 24, 2020
5d62492
fix typo
RalfJung Oct 24, 2020
849c929
move UnsafeCell-in-const check from interning to validation
RalfJung Oct 24, 2020
7b4c397
Do not try to report on closures to avoid ICE
JohnTitor Oct 23, 2020
4ec396e
Test with NLL explicitly
JohnTitor Oct 25, 2020
e218380
Make some functions private that don't have to be public
jyn514 Oct 25, 2020
341170d
move &mut-in-const check from interning to validation
RalfJung Oct 25, 2020
7c7b90d
interning cleanup: we no longer need to distinguish Const and ConstIn…
RalfJung Oct 25, 2020
db01d97
explain why interning is not as trivial as it might seem
RalfJung Oct 25, 2020
3bd5cc9
also test non-extern uninhabited statics
RalfJung Oct 25, 2020
b9e7982
Rollup merge of #78214 - estebank:match-semicolon, r=oli-obk
Dylan-DPC Oct 25, 2020
117ce17
Rollup merge of #78227 - SergioBenitez:test-stdout-threading, r=m-ou-se
Dylan-DPC Oct 25, 2020
9fe1de1
Rollup merge of #78247 - simonvandel:fix-78192, r=oli-obk
Dylan-DPC Oct 25, 2020
93b4abf
Rollup merge of #78268 - JohnTitor:issue-78262, r=estebank
Dylan-DPC Oct 25, 2020
da10bd8
Rollup merge of #78324 - RalfJung:uninhabited-statics, r=oli-obk
Dylan-DPC Oct 25, 2020
9c08ed0
Rollup merge of #78348 - jyn514:pub-crate, r=GuillaumeGomez
Dylan-DPC Oct 25, 2020
04fe7fa
Rollup merge of #78351 - RalfJung:validity-unsafe-cell, r=oli-obk
Dylan-DPC Oct 25, 2020
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
223 changes: 171 additions & 52 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};

use crate::infer;
use crate::infer::OriginalQueryValues;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
StatementAsExpression,
};

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
Expand All @@ -64,7 +64,6 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ParamEnvAnd;
use rustc_middle::ty::{
self,
subst::{Subst, SubstsRef},
Expand Down Expand Up @@ -688,13 +687,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
};
let msg = "`match` arms have incompatible types";
err.span_label(outer_error_span, msg);
if let Some(sp) = semi_span {
err.span_suggestion_short(
sp,
"consider removing this semicolon",
String::new(),
Applicability::MachineApplicable,
);
if let Some((sp, boxed)) = semi_span {
if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) =
(boxed, &prior_arms[..])
{
err.multipart_suggestion(
"consider removing this semicolon and boxing the expressions",
vec![
(prior_arm.shrink_to_lo(), "Box::new(".to_string()),
(prior_arm.shrink_to_hi(), ")".to_string()),
(arm_span.shrink_to_lo(), "Box::new(".to_string()),
(arm_span.shrink_to_hi(), ")".to_string()),
(sp, String::new()),
],
Applicability::HasPlaceholders,
);
} else if matches!(boxed, StatementAsExpression::NeedsBoxing) {
err.span_suggestion_short(
sp,
"consider removing this semicolon and boxing the expressions",
String::new(),
Applicability::MachineApplicable,
);
} else {
err.span_suggestion_short(
sp,
"consider removing this semicolon",
String::new(),
Applicability::MachineApplicable,
);
}
}
if let Some(ret_sp) = opt_suggest_box_span {
// Get return type span and point to it.
Expand All @@ -717,13 +739,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if let Some(sp) = outer {
err.span_label(sp, "`if` and `else` have incompatible types");
}
if let Some(sp) = semicolon {
err.span_suggestion_short(
sp,
"consider removing this semicolon",
String::new(),
Applicability::MachineApplicable,
);
if let Some((sp, boxed)) = semicolon {
if matches!(boxed, StatementAsExpression::NeedsBoxing) {
err.multipart_suggestion(
"consider removing this semicolon and boxing the expression",
vec![
(then.shrink_to_lo(), "Box::new(".to_string()),
(then.shrink_to_hi(), ")".to_string()),
(else_sp.shrink_to_lo(), "Box::new(".to_string()),
(else_sp.shrink_to_hi(), ")".to_string()),
(sp, String::new()),
],
Applicability::MachineApplicable,
);
} else {
err.span_suggestion_short(
sp,
"consider removing this semicolon",
String::new(),
Applicability::MachineApplicable,
);
}
}
if let Some(ret_sp) = opt_suggest_box_span {
self.suggest_boxing_for_return_impl_trait(
Expand Down Expand Up @@ -1602,6 +1638,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Mismatch::Variable(exp_found) => Some(exp_found),
Mismatch::Fixed(_) => None,
};
let exp_found = match terr {
// `terr` has more accurate type information than `exp_found` in match expressions.
ty::error::TypeError::Sorts(terr)
if exp_found.map_or(false, |ef| terr.found == ef.found) =>
{
Some(*terr)
}
_ => exp_found,
};
debug!("exp_found {:?} terr {:?}", exp_found, terr);
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
Expand All @@ -1623,6 +1669,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.note_error_origin(diag, cause, exp_found);
}

fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
if let ty::Opaque(def_id, substs) = ty.kind() {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
// Future::Output
let item_def_id = self
.tcx
.associated_items(future_trait)
.in_definition_order()
.next()
.unwrap()
.def_id;

let bounds = self.tcx.explicit_item_bounds(*def_id);

for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx, substs);
if let ty::PredicateAtom::Projection(projection_predicate) =
predicate.skip_binders()
{
if projection_predicate.projection_ty.item_def_id == item_def_id {
// We don't account for multiple `Future::Output = Ty` contraints.
return Some(projection_predicate.ty);
}
}
}
}
None
}

/// A possible error is to forget to add `.await` when using futures:
///
/// ```
/// async fn make_u32() -> u32 {
/// 22
/// }
///
/// fn take_u32(x: u32) {}
///
/// async fn foo() {
/// let x = make_u32();
/// take_u32(x);
/// }
/// ```
///
/// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
/// expected type. If this is the case, and we are inside of an async body, it suggests adding
/// `.await` to the tail of the expression.
fn suggest_await_on_expect_found(
&self,
cause: &ObligationCause<'tcx>,
Expand All @@ -1632,50 +1725,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) {
debug!(
"suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
exp_span, exp_found.expected, exp_found.found
exp_span, exp_found.expected, exp_found.found,
);

if let ty::Opaque(def_id, _) = *exp_found.expected.kind() {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
// Future::Output
let item_def_id = self
.tcx
.associated_items(future_trait)
.in_definition_order()
.next()
.unwrap()
.def_id;
if let ObligationCauseCode::CompareImplMethodObligation { .. } = &cause.code {
return;
}

let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id));
if let Some(projection_ty) = projection_ty {
let projection_query = self.canonicalize_query(
&ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty },
&mut OriginalQueryValues::default(),
);
if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) {
let normalized_ty = resp.value.value.normalized_ty;
debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty);
if ty::TyS::same_type(normalized_ty, exp_found.found) {
let span = if let ObligationCauseCode::Pattern {
span,
origin_expr: _,
root_ty: _,
} = cause.code
{
// scrutinee's span
span.unwrap_or(exp_span)
} else {
exp_span
};
diag.span_suggestion_verbose(
span.shrink_to_hi(),
"consider awaiting on the future",
".await".to_string(),
match (
self.get_impl_future_output_ty(exp_found.expected),
self.get_impl_future_output_ty(exp_found.found),
) {
(Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
diag.multipart_suggestion(
"consider `await`ing on both `Future`s",
vec![
(then.shrink_to_hi(), ".await".to_string()),
(exp_span.shrink_to_hi(), ".await".to_string()),
],
Applicability::MaybeIncorrect,
);
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
prior_arms,
..
}) => {
if let [.., arm_span] = &prior_arms[..] {
diag.multipart_suggestion(
"consider `await`ing on both `Future`s",
vec![
(arm_span.shrink_to_hi(), ".await".to_string()),
(exp_span.shrink_to_hi(), ".await".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
diag.help("consider `await`ing on both `Future`s");
}
}
_ => {
diag.help("consider `await`ing on both `Future`s");
}
},
(_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
let span = match cause.code {
// scrutinee's span
ObligationCauseCode::Pattern { span: Some(span), .. } => span,
_ => exp_span,
};
diag.span_suggestion_verbose(
span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await".to_string(),
Applicability::MaybeIncorrect,
);
}
(Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => {
let span = match cause.code {
// scrutinee's span
ObligationCauseCode::Pattern { span: Some(span), .. } => span,
_ => exp_span,
};
diag.span_suggestion_verbose(
span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await".to_string(),
Applicability::MaybeIncorrect,
);
}
_ => {}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
) if **sub_r == RegionKind::ReStatic => {
// This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
// This may have a closure and it would cause ICE
// through `find_param_with_region` (#78262).
let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
if fn_returns.is_empty() {
return None;
}

let param = self.find_param_with_region(sup_r, sub_r)?;
let lifetime = if sup_r.has_name() {
format!("lifetime `{}`", sup_r)
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ impl Write for Sink {
Ok(())
}
}
impl io::LocalOutput for Sink {
fn clone_box(&self) -> Box<dyn io::LocalOutput> {
Box::new(Self(self.0.clone()))
}
}

/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
/// for `'static` bounds.
Expand Down
12 changes: 0 additions & 12 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,6 @@ pub struct Body<'tcx> {
/// We hold in this field all the constants we are not able to evaluate yet.
pub required_consts: Vec<Constant<'tcx>>,

/// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because
/// we'd statically know that no thing with interior mutability will ever be available to the
/// user without some serious unsafe code. Now this means that our promoted is actually
/// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because
/// the index may be a runtime value. Such a promoted value is illegal because it has reachable
/// interior mutability. This flag just makes this situation very obvious where the previous
/// implementation without the flag hid this situation silently.
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
pub ignore_interior_mut_in_const_validation: bool,

/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
///
/// Note that this does not actually mean that this body is not computable right now.
Expand Down Expand Up @@ -276,7 +266,6 @@ impl<'tcx> Body<'tcx> {
var_debug_info,
span,
required_consts: Vec::new(),
ignore_interior_mut_in_const_validation: false,
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
};
Expand Down Expand Up @@ -306,7 +295,6 @@ impl<'tcx> Body<'tcx> {
required_consts: Vec::new(),
generator_kind: None,
var_debug_info: Vec::new(),
ignore_interior_mut_in_const_validation: false,
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
};
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,24 @@ impl ObligationCauseCode<'_> {
#[cfg(target_arch = "x86_64")]
static_assert_size!(ObligationCauseCode<'_>, 32);

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum StatementAsExpression {
CorrectType,
NeedsBoxing,
}

impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
type Lifted = StatementAsExpression;
fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
Some(self)
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span,
pub scrut_span: Span,
pub semi_span: Option<Span>,
pub semi_span: Option<(Span, StatementAsExpression)>,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
Expand All @@ -357,7 +370,7 @@ pub struct IfExpressionCause {
pub then: Span,
pub else_sp: Span,
pub outer: Option<Span>,
pub semicolon: Option<Span>,
pub semicolon: Option<(Span, StatementAsExpression)>,
pub opt_suggest_box_span: Option<Span>,
}

Expand Down
Loading