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 5 pull requests #71012

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9dc9785
Handle `impl Trait` where `Trait` has an assoc type with missing bounds
estebank Mar 4, 2020
02711fd
review comments
estebank Apr 5, 2020
02ccf86
review comments
estebank Apr 5, 2020
f26c855
Account for type params with bounds
estebank Apr 5, 2020
ba755a8
Account for existing names when suggesting adding a type param
estebank Apr 5, 2020
5e07be4
Try to use the first char in the trait name as type param
estebank Apr 5, 2020
c829db3
review comments
estebank Apr 5, 2020
8a03147
Normalize MIR locals' types for generator layout computation.
oli-obk Apr 9, 2020
68b38c3
Normalize function signature in function casting check
ldm0 Apr 10, 2020
75cc403
Tidy fix
ldm0 Apr 10, 2020
6e70849
tests encoding current behavior for various cases of "binding" to _.
pnkfelix Feb 29, 2020
ee7a035
Update src/test/ui/binding/issue-53114-borrow-checks.rs
pnkfelix Mar 5, 2020
192d533
Update src/test/ui/binding/issue-53114-safety-checks.rs
pnkfelix Mar 5, 2020
1ff99b7
copy test cases to `if let` as well.
pnkfelix Mar 5, 2020
22ea3a4
--bless you
Centril Apr 10, 2020
7de9511
added machine hooks to track deallocations
RustyYato Apr 9, 2020
b46a7cb
review comments
estebank Apr 10, 2020
dae7bf3
Rollup merge of #69573 - pnkfelix:issue-53114-add-tests, r=Centril
Dylan-DPC Apr 10, 2020
6e49b91
Rollup merge of #69707 - estebank:impl-trait-missing-bounds, r=Centril
Dylan-DPC Apr 10, 2020
d4e8c93
Rollup merge of #70957 - oli-obk:lazy_repeat_length_eval_ice, r=matth…
Dylan-DPC Apr 10, 2020
12e3c7b
Rollup merge of #70962 - KrishnaSannasi:track-dealloc, r=RalfJung
Dylan-DPC Apr 10, 2020
2af0b16
Rollup merge of #70982 - ldm0:fncoerce, r=eddyb
Dylan-DPC Apr 10, 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
8 changes: 8 additions & 0 deletions src/librustc_mir/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
kind: Option<MemoryKind<Self::MemoryKind>>,
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);

/// Called to notify the machine before a deallocation occurs.
fn before_deallocation(
_memory_extra: &mut Self::MemoryExtra,
_id: AllocId,
) -> InterpResult<'tcx> {
Ok(())
}

/// Return the "base" tag for the given *global* allocation: the one that is used for direct
/// accesses to this static/const/fn allocation. If `id` is not a global allocation,
/// this will return an unusable tag (i.e., accesses will be UB)!
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
);
}

M::before_deallocation(&mut self.extra, ptr.alloc_id)?;

let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
Some(alloc) => alloc,
None => {
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,15 +721,18 @@ fn compute_layout<'tcx>(
_ => bug!(),
};

let param_env = tcx.param_env(source.def_id());

for (local, decl) in body.local_decls.iter_enumerated() {
// Ignore locals which are internal or not live
if !live_locals.contains(local) || decl.internal {
continue;
}
let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);

// Sanity check that typeck knows about the type of locals which are
// live across a suspension point
if !allowed.contains(&decl.ty) && !allowed_upvars.contains(&decl.ty) {
if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) {
span_bug!(
body.span,
"Broken MIR: generator contains type {} in MIR, \
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trait_selection/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![feature(or_patterns)]
#![feature(str_strip)]
#![feature(option_zip)]
#![recursion_limit = "512"] // For rustdoc

#[macro_use]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trait_selection/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// which is somewhat confusing.
self.suggest_restricting_param_bound(
&mut err,
&trait_ref,
trait_ref,
obligation.cause.body_id,
);
} else {
Expand Down
206 changes: 174 additions & 32 deletions src/librustc_trait_selection/traits/error_reporting/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_middle::ty::TypeckTables;
use rustc_middle::ty::{
self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;

Expand All @@ -27,7 +27,7 @@ pub trait InferCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
&self,
err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::PolyTraitRef<'_>,
trait_ref: ty::PolyTraitRef<'_>,
body_id: hir::HirId,
);

Expand Down Expand Up @@ -148,11 +148,128 @@ pub trait InferCtxtExt<'tcx> {
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
}

fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
(
generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
format!(
"{} {} ",
if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
pred,
),
)
}

/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but
/// it can also be an `impl Trait` param that needs to be decomposed to a type
/// param for cleaner code.
fn suggest_restriction(
generics: &hir::Generics<'_>,
msg: &str,
err: &mut DiagnosticBuilder<'_>,
fn_sig: Option<&hir::FnSig<'_>>,
projection: Option<&ty::ProjectionTy<'_>>,
trait_ref: ty::PolyTraitRef<'_>,
) {
let span = generics.where_clause.span_for_predicates_or_empty_place();
if span.from_expansion() || span.desugaring_kind().is_some() {
return;
}
// Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
if let Some((bound_str, fn_sig)) =
fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind {
// Shenanigans to get the `Trait` from the `impl Trait`.
ty::Param(param) => {
// `fn foo(t: impl Trait)`
// ^^^^^ get this string
param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
}
_ => None,
})
{
// We know we have an `impl Trait` that doesn't satisfy a required projection.

// Find all of the ocurrences of `impl Trait` for `Trait` in the function arguments'
// types. There should be at least one, but there might be *more* than one. In that
// case we could just ignore it and try to identify which one needs the restriction,
// but instead we choose to suggest replacing all instances of `impl Trait` with `T`
// where `T: Trait`.
let mut ty_spans = vec![];
let impl_trait_str = format!("impl {}", bound_str);
for input in fn_sig.decl.inputs {
if let hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { segments: [segment], .. },
)) = input.kind
{
if segment.ident.as_str() == impl_trait_str.as_str() {
// `fn foo(t: impl Trait)`
// ^^^^^^^^^^ get this to suggest `T` instead

// There might be more than one `impl Trait`.
ty_spans.push(input.span);
}
}
}

let type_param_name = generics.params.next_type_param_name(Some(&bound_str));
// The type param `T: Trait` we will suggest to introduce.
let type_param = format!("{}: {}", type_param_name, bound_str);

// FIXME: modify the `trait_ref` instead of string shenanigans.
// Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
let pred = trait_ref.without_const().to_predicate().to_string();
let pred = pred.replace(&impl_trait_str, &type_param_name);
let mut sugg = vec![
match generics
.params
.iter()
.filter(|p| match p.kind {
hir::GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
..
} => false,
_ => true,
})
.last()
{
// `fn foo(t: impl Trait)`
// ^ suggest `<T: Trait>` here
None => (generics.span, format!("<{}>", type_param)),
// `fn foo<A>(t: impl Trait)`
// ^^^ suggest `<A, T: Trait>` here
Some(param) => (
param.bounds_span().unwrap_or(param.span).shrink_to_hi(),
format!(", {}", type_param),
),
},
// `fn foo(t: impl Trait)`
// ^ suggest `where <T as Trait>::A: Bound`
predicate_constraint(generics, pred),
];
sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));

// Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.
// FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest
// `fn foo(t: impl Trait<A: Bound>)` instead.
err.multipart_suggestion(
"introduce a type parameter with a trait bound instead of using `impl Trait`",
sugg,
Applicability::MaybeIncorrect,
);
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
let (sp, sugg) =
predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string());
let appl = Applicability::MachineApplicable;
err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl);
}
}

impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
fn suggest_restricting_param_bound(
&self,
mut err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::PolyTraitRef<'_>,
trait_ref: ty::PolyTraitRef<'_>,
body_id: hir::HirId,
) {
let self_ty = trait_ref.self_ty();
Expand All @@ -162,27 +279,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
_ => return,
};

let suggest_restriction =
|generics: &hir::Generics<'_>, msg, err: &mut DiagnosticBuilder<'_>| {
let span = generics.where_clause.span_for_predicates_or_empty_place();
if !span.from_expansion() && span.desugaring_kind().is_none() {
err.span_suggestion(
generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
&format!("consider further restricting {}", msg),
format!(
"{} {} ",
if !generics.where_clause.predicates.is_empty() {
","
} else {
" where"
},
trait_ref.without_const().to_predicate(),
),
Applicability::MachineApplicable,
);
}
};

// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
// don't suggest `T: Sized + ?Sized`.
let mut hir_id = body_id;
Expand All @@ -194,27 +290,47 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
..
}) if param_ty && self_ty == self.tcx.types.self_param => {
// Restricting `Self` for a single method.
suggest_restriction(&generics, "`Self`", err);
suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref);
return;
}

hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Fn(..),
kind: hir::TraitItemKind::Fn(fn_sig, ..),
..
})
| hir::Node::ImplItem(hir::ImplItem {
generics,
kind: hir::ImplItemKind::Fn(..),
kind: hir::ImplItemKind::Fn(fn_sig, ..),
..
})
| hir::Node::Item(
hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }
| hir::Item { kind: hir::ItemKind::Trait(_, _, generics, _, _), .. }
| hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(fn_sig, generics, _), ..
}) if projection.is_some() => {
// Missing restriction on associated type of type parameter (unmet projection).
suggest_restriction(
&generics,
"the associated type",
err,
Some(fn_sig),
projection,
trait_ref,
);
return;
}
hir::Node::Item(
hir::Item { kind: hir::ItemKind::Trait(_, _, generics, _, _), .. }
| hir::Item { kind: hir::ItemKind::Impl { generics, .. }, .. },
) if projection.is_some() => {
// Missing associated type bound.
suggest_restriction(&generics, "the associated type", err);
// Missing restriction on associated type of type parameter (unmet projection).
suggest_restriction(
&generics,
"the associated type",
err,
None,
projection,
trait_ref,
);
return;
}

Expand Down Expand Up @@ -1588,3 +1704,29 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
hir::intravisit::walk_body(self, body);
}
}

pub trait NextTypeParamName {
fn next_type_param_name(&self, name: Option<&str>) -> String;
}

impl NextTypeParamName for &[hir::GenericParam<'_>] {
fn next_type_param_name(&self, name: Option<&str>) -> String {
// This is the whitelist of possible parameter names that we might suggest.
let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase());
let name = name.as_ref().map(|s| s.as_str());
let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
let used_names = self
.iter()
.filter_map(|p| match p.name {
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
})
.collect::<Vec<_>>();

possible_names
.iter()
.find(|n| !used_names.contains(&Symbol::intern(n)))
.unwrap_or(&"ParamName")
.to_string()
}
}
5 changes: 4 additions & 1 deletion src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
match self.expr_ty.kind {
ty::FnDef(..) => {
// Attempt a coercion to a fn pointer type.
let f = self.expr_ty.fn_sig(fcx.tcx);
let f = fcx.normalize_associated_types_in(
self.expr.span,
&self.expr_ty.fn_sig(fcx.tcx),
);
let res = fcx.try_coerce(
self.expr,
self.expr_ty,
Expand Down
16 changes: 2 additions & 14 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;

mod type_of;

Expand Down Expand Up @@ -135,20 +136,7 @@ crate fn placeholder_type_error(
if placeholder_types.is_empty() {
return;
}
// This is the whitelist of possible parameter names that we might suggest.
let possible_names = ["T", "K", "L", "A", "B", "C"];
let used_names = generics
.iter()
.filter_map(|p| match p.name {
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
})
.collect::<Vec<_>>();

let type_name = possible_names
.iter()
.find(|n| !used_names.contains(&Symbol::intern(n)))
.unwrap_or(&"ParamName");
let type_name = generics.next_type_param_name(None);

let mut sugg: Vec<_> =
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
Expand Down
Loading