Auto merge of #67970 - cjgillot:inherent, r=Centril

Minimize dependencies on trait and infer inside librustc

Split from #67953

All commits should pass check on their own.

r? @Centril
This commit is contained in:
bors
2020-01-07 21:23:19 +00:00
42 changed files with 1553 additions and 1483 deletions
+203 -200
View File
@@ -53,6 +53,8 @@
use crate::infer::opaque_types;
use crate::infer::{self, SuppressRegionErrors};
use crate::middle::region;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::object_safety_violations;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
};
@@ -79,212 +81,209 @@
pub mod nice_region_error;
impl<'tcx> TyCtxt<'tcx> {
pub fn note_and_explain_region(
self,
region_scope_tree: &region::ScopeTree,
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
) {
let (description, span) = match *region {
ty::ReScope(scope) => {
let new_string;
let unknown_scope = || {
format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix)
};
let span = scope.span(self, region_scope_tree);
let tag = match self.hir().find(scope.hir_id(region_scope_tree)) {
Some(Node::Block(_)) => "block",
Some(Node::Expr(expr)) => match expr.kind {
hir::ExprKind::Call(..) => "call",
hir::ExprKind::MethodCall(..) => "method call",
hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
hir::ExprKind::Match(..) => "match",
_ => "expression",
},
Some(Node::Stmt(_)) => "statement",
Some(Node::Item(it)) => Self::item_scope_tag(&it),
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
Some(_) | None => {
err.span_note(span, &unknown_scope());
return;
}
};
let scope_decorated_tag = match scope.data {
region::ScopeData::Node => tag,
region::ScopeData::CallSite => "scope of call-site for function",
region::ScopeData::Arguments => "scope of function body",
region::ScopeData::Destruction => {
new_string = format!("destruction scope surrounding {}", tag);
&new_string[..]
}
region::ScopeData::Remainder(first_statement_index) => {
new_string = format!(
"block suffix following statement {}",
first_statement_index.index()
);
&new_string[..]
}
};
self.explain_span(scope_decorated_tag, span)
}
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
self.msg_span_from_free_region(region)
}
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
ty::RePlaceholder(_) => (format!("any other region"), None),
// FIXME(#13998) RePlaceholder should probably print like
// ReFree rather than dumping Debug output on the user.
//
// We shouldn't really be having unification failures with ReVar
// and ReLateBound though.
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
(format!("lifetime {:?}", region), None)
}
// We shouldn't encounter an error message with ReClosureBound.
ty::ReClosureBound(..) => {
bug!("encountered unexpected ReClosureBound: {:?}", region,);
}
};
TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
}
pub fn note_and_explain_free_region(
self,
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
) {
let (description, span) = self.msg_span_from_free_region(region);
TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
}
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) => {
self.msg_span_from_early_bound_and_free_regions(region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
_ => bug!("{:?}", region),
}
}
fn msg_span_from_early_bound_and_free_regions(
self,
region: ty::Region<'tcx>,
) -> (String, Option<Span>) {
let cm = self.sess.source_map();
let scope = region.free_region_binding_scope(self);
let node = self.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
let tag = match self.hir().find(node) {
Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
Some(Node::Item(it)) => Self::item_scope_tag(&it),
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
_ => unreachable!(),
};
let (prefix, span) = match *region {
ty::ReEarlyBound(ref br) => {
let mut sp = cm.def_span(self.hir().span(node));
if let Some(param) =
self.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
{
sp = param.span;
pub(super) fn note_and_explain_region(
tcx: TyCtxt<'tcx>,
region_scope_tree: &region::ScopeTree,
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
) {
let (description, span) = match *region {
ty::ReScope(scope) => {
let new_string;
let unknown_scope =
|| format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix);
let span = scope.span(tcx, region_scope_tree);
let tag = match tcx.hir().find(scope.hir_id(region_scope_tree)) {
Some(Node::Block(_)) => "block",
Some(Node::Expr(expr)) => match expr.kind {
hir::ExprKind::Call(..) => "call",
hir::ExprKind::MethodCall(..) => "method call",
hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
hir::ExprKind::Match(..) => "match",
_ => "expression",
},
Some(Node::Stmt(_)) => "statement",
Some(Node::Item(it)) => item_scope_tag(&it),
Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
Some(_) | None => {
err.span_note(span, &unknown_scope());
return;
}
(format!("the lifetime `{}` as defined on", br.name), sp)
}
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(_, name), ..
}) => {
let mut sp = cm.def_span(self.hir().span(node));
if let Some(param) =
self.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
{
sp = param.span;
};
let scope_decorated_tag = match scope.data {
region::ScopeData::Node => tag,
region::ScopeData::CallSite => "scope of call-site for function",
region::ScopeData::Arguments => "scope of function body",
region::ScopeData::Destruction => {
new_string = format!("destruction scope surrounding {}", tag);
&new_string[..]
}
(format!("the lifetime `{}` as defined on", name), sp)
region::ScopeData::Remainder(first_statement_index) => {
new_string = format!(
"block suffix following statement {}",
first_statement_index.index()
);
&new_string[..]
}
};
explain_span(tcx, scope_decorated_tag, span)
}
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
msg_span_from_free_region(tcx, region)
}
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
ty::RePlaceholder(_) => (format!("any other region"), None),
// FIXME(#13998) RePlaceholder should probably print like
// ReFree rather than dumping Debug output on the user.
//
// We shouldn't really be having unification failures with ReVar
// and ReLateBound though.
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
(format!("lifetime {:?}", region), None)
}
// We shouldn't encounter an error message with ReClosureBound.
ty::ReClosureBound(..) => {
bug!("encountered unexpected ReClosureBound: {:?}", region,);
}
};
emit_msg_span(err, prefix, description, span, suffix);
}
pub(super) fn note_and_explain_free_region(
tcx: TyCtxt<'tcx>,
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
) {
let (description, span) = msg_span_from_free_region(tcx, region);
emit_msg_span(err, prefix, description, span, suffix);
}
fn msg_span_from_free_region(
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
) -> (String, Option<Span>) {
match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) => {
msg_span_from_early_bound_and_free_regions(tcx, region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
_ => bug!("{:?}", region),
}
}
fn msg_span_from_early_bound_and_free_regions(
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
) -> (String, Option<Span>) {
let cm = tcx.sess.source_map();
let scope = region.free_region_binding_scope(tcx);
let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
let tag = match tcx.hir().find(node) {
Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
Some(Node::Item(it)) => item_scope_tag(&it),
Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
_ => unreachable!(),
};
let (prefix, span) = match *region {
ty::ReEarlyBound(ref br) => {
let mut sp = cm.def_span(tcx.hir().span(node));
if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
{
sp = param.span;
}
ty::ReFree(ref fr) => match fr.bound_region {
ty::BrAnon(idx) => (
format!("the anonymous lifetime #{} defined on", idx + 1),
self.hir().span(node),
),
_ => (
format!("the lifetime `{}` as defined on", region),
cm.def_span(self.hir().span(node)),
),
},
_ => bug!(),
};
let (msg, opt_span) = self.explain_span(tag, span);
(format!("{} {}", prefix, msg), opt_span)
}
fn emit_msg_span(
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
description: String,
span: Option<Span>,
suffix: &str,
) {
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {
err.span_note(span, &message);
} else {
err.note(&message);
(format!("the lifetime `{}` as defined on", br.name), sp)
}
}
fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
match item.kind {
hir::ItemKind::Impl(..) => "impl",
hir::ItemKind::Struct(..) => "struct",
hir::ItemKind::Union(..) => "union",
hir::ItemKind::Enum(..) => "enum",
hir::ItemKind::Trait(..) => "trait",
hir::ItemKind::Fn(..) => "function body",
_ => "item",
ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => {
let mut sp = cm.def_span(tcx.hir().span(node));
if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
{
sp = param.span;
}
(format!("the lifetime `{}` as defined on", name), sp)
}
}
ty::ReFree(ref fr) => match fr.bound_region {
ty::BrAnon(idx) => {
(format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node))
}
_ => (
format!("the lifetime `{}` as defined on", region),
cm.def_span(tcx.hir().span(node)),
),
},
_ => bug!(),
};
let (msg, opt_span) = explain_span(tcx, tag, span);
(format!("{} {}", prefix, msg), opt_span)
}
fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
match item.kind {
hir::TraitItemKind::Method(..) => "method body",
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
}
}
fn emit_msg_span(
err: &mut DiagnosticBuilder<'_>,
prefix: &str,
description: String,
span: Option<Span>,
suffix: &str,
) {
let message = format!("{}{}{}", prefix, description, suffix);
fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
match item.kind {
hir::ImplItemKind::Method(..) => "method body",
hir::ImplItemKind::Const(..)
| hir::ImplItemKind::OpaqueTy(..)
| hir::ImplItemKind::TyAlias(..) => "associated item",
}
if let Some(span) = span {
err.span_note(span, &message);
} else {
err.note(&message);
}
}
fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) {
let lo = self.sess.source_map().lookup_char_pos(span.lo());
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
match item.kind {
hir::ItemKind::Impl(..) => "impl",
hir::ItemKind::Struct(..) => "struct",
hir::ItemKind::Union(..) => "union",
hir::ItemKind::Enum(..) => "enum",
hir::ItemKind::Trait(..) => "trait",
hir::ItemKind::Fn(..) => "function body",
_ => "item",
}
}
fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
match item.kind {
hir::TraitItemKind::Method(..) => "method body",
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
}
}
fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
match item.kind {
hir::ImplItemKind::Method(..) => "method body",
hir::ImplItemKind::Const(..)
| hir::ImplItemKind::OpaqueTy(..)
| hir::ImplItemKind::TyAlias(..) => "associated item",
}
}
fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) {
let lo = tcx.sess.source_map().lookup_char_pos(span.lo());
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_region_errors(
&self,
@@ -1489,8 +1488,8 @@ pub fn report_and_explain_type_error(
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0038(did) => {
let violations = self.tcx.object_safety_violations(did);
self.tcx.report_object_safety_error(span, did, violations)
let violations = object_safety_violations(self.tcx, did);
report_object_safety_error(self.tcx, span, did, violations)
}
FailureCode::Error0317(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
@@ -1719,7 +1718,8 @@ fn binding_suggestion<'tcx, S: fmt::Display>(
"consider adding an explicit lifetime bound for `{}`",
bound_kind
));
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
&format!("{} must be valid for ", labeled_user_string),
@@ -1747,7 +1747,8 @@ fn report_sub_sup_conflict(
) {
let mut err = self.report_inference_failure(var_origin);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"first, the lifetime cannot outlive ",
@@ -1771,7 +1772,8 @@ fn report_sub_sup_conflict(
(self.values_str(&sup_trace.values), self.values_str(&sub_trace.values))
{
if sub_expected == sup_expected && sub_found == sup_found {
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...but the lifetime must also be valid for ",
@@ -1794,7 +1796,8 @@ fn report_sub_sup_conflict(
self.note_region_origin(&mut err, &sup_origin);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"but, the lifetime must be valid for ",
@@ -1,5 +1,6 @@
//! Error Reporting for static impl Traits.
use crate::infer::error_reporting::msg_span_from_free_region;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::ty::{BoundRegion, FreeRegion, RegionKind};
@@ -32,7 +33,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
);
err.span_label(sup_origin.span(), "...but this borrow...");
let (lifetime, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup_r);
let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r);
if let Some(lifetime_sp) = lt_sp_opt {
err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime));
}
+70 -35
View File
@@ -1,3 +1,4 @@
use crate::infer::error_reporting::note_and_explain_region;
use crate::infer::{self, InferCtxt, SubregionOrigin};
use crate::middle::region;
use crate::ty::error::TypeError;
@@ -167,8 +168,9 @@ pub(super) fn report_concrete_failure(
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, &terr);
self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "...");
self.tcx.note_and_explain_region(
note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "...");
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...does not necessarily outlive ",
@@ -185,14 +187,16 @@ pub(super) fn report_concrete_failure(
"lifetime of reference outlives lifetime of \
borrowed content..."
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...the reference is valid for ",
sub,
"...",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...but the borrowed content is only valid for ",
@@ -211,14 +215,16 @@ pub(super) fn report_concrete_failure(
of captured variable `{}`...",
var_name
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...the borrowed pointer is valid for ",
sub,
"...",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
&format!("...but `{}` is only valid for ", var_name),
@@ -230,14 +236,16 @@ pub(super) fn report_concrete_failure(
infer::InfStackClosure(span) => {
let mut err =
struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...the closure must be valid for ",
sub,
"...",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"...but the closure's stack frame is only valid \
@@ -254,7 +262,8 @@ pub(super) fn report_concrete_failure(
E0315,
"cannot invoke closure outside of its lifetime"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the closure is only valid for ",
@@ -270,7 +279,8 @@ pub(super) fn report_concrete_failure(
E0473,
"dereference of reference outside its lifetime"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the reference is only valid for ",
@@ -288,14 +298,16 @@ pub(super) fn report_concrete_failure(
enclosing closure",
self.tcx.hir().name(id)
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"captured variable is valid for ",
sup,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"closure is valid for ",
@@ -311,7 +323,8 @@ pub(super) fn report_concrete_failure(
E0475,
"index of slice outside its lifetime"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the slice is only valid for ",
@@ -328,14 +341,16 @@ pub(super) fn report_concrete_failure(
"lifetime of the source pointer does not outlive \
lifetime bound of the object type"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"object type is valid for ",
sub,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"source pointer is only valid for ",
@@ -354,14 +369,16 @@ pub(super) fn report_concrete_failure(
self.ty_to_string(ty)
);
match *sub {
ty::ReStatic => self.tcx.note_and_explain_region(
ty::ReStatic => note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"type must satisfy ",
sub,
"",
),
_ => self.tcx.note_and_explain_region(
_ => note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"type must outlive ",
@@ -374,14 +391,16 @@ pub(super) fn report_concrete_failure(
infer::RelateRegionParamBound(span) => {
let mut err =
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"lifetime parameter instantiated with ",
sup,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"but lifetime parameter must outlive ",
@@ -399,7 +418,8 @@ pub(super) fn report_concrete_failure(
parameter) is not valid at this point",
self.ty_to_string(ty)
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"type must outlive ",
@@ -416,7 +436,8 @@ pub(super) fn report_concrete_failure(
"lifetime of method receiver does not outlive the \
method call"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the receiver is only valid for ",
@@ -433,7 +454,8 @@ pub(super) fn report_concrete_failure(
"lifetime of function argument does not outlive \
the function call"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the function argument is only valid for ",
@@ -450,7 +472,8 @@ pub(super) fn report_concrete_failure(
"lifetime of return value does not outlive the \
function call"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the return value is only valid for ",
@@ -467,7 +490,8 @@ pub(super) fn report_concrete_failure(
"lifetime of operand does not outlive the \
operation"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the operand is only valid for ",
@@ -483,7 +507,8 @@ pub(super) fn report_concrete_failure(
E0484,
"reference is not valid at the time of borrow"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the borrow is only valid for ",
@@ -500,7 +525,8 @@ pub(super) fn report_concrete_failure(
"automatically reference is not valid at the time \
of borrow"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the automatic borrow is only valid for ",
@@ -518,7 +544,8 @@ pub(super) fn report_concrete_failure(
not valid during the expression: `{}`",
self.ty_to_string(t)
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"type is only valid for ",
@@ -536,14 +563,16 @@ pub(super) fn report_concrete_failure(
called while references are dead"
);
// FIXME (22171): terms "super/subregion" are suboptimal
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"superregion: ",
sup,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"subregion: ",
@@ -560,7 +589,8 @@ pub(super) fn report_concrete_failure(
"lifetime of variable does not enclose its \
declaration"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the variable is only valid for ",
@@ -576,7 +606,8 @@ pub(super) fn report_concrete_failure(
E0489,
"type/lifetime parameter not in scope here"
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the parameter is only valid for ",
@@ -593,14 +624,16 @@ pub(super) fn report_concrete_failure(
"a value of type `{}` is borrowed for too long",
self.ty_to_string(ty)
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the type is valid for ",
sub,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"but the borrow lasts for ",
@@ -618,14 +651,16 @@ pub(super) fn report_concrete_failure(
than the data it references",
self.ty_to_string(ty)
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"the pointer is valid for ",
sub,
"",
);
self.tcx.note_and_explain_region(
note_and_explain_region(
self.tcx,
region_scope_tree,
&mut err,
"but the referenced data is only valid for ",
+73 -5
View File
@@ -1,8 +1,9 @@
use crate::infer::outlives::free_region_map::FreeRegionRelations;
use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region};
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
use crate::middle::region;
use crate::traits::{self, PredicateObligation};
use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::free_region_map::FreeRegionRelations;
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
use errors::DiagnosticBuilder;
@@ -349,7 +350,8 @@ pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
debug!("constrain_opaque_type: bounds={:#?}", bounds);
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
let required_region_bounds = tcx.required_region_bounds(opaque_type, bounds.predicates);
let required_region_bounds =
required_region_bounds(tcx, opaque_type, bounds.predicates);
debug_assert!(!required_region_bounds.is_empty());
for required_region in required_region_bounds {
@@ -624,7 +626,8 @@ pub fn unexpected_hidden_region_diagnostic(
//
// (*) if not, the `tainted_by_errors` flag would be set to
// true in any case, so we wouldn't be here at all.
tcx.note_and_explain_free_region(
note_and_explain_free_region(
tcx,
&mut err,
&format!("hidden type `{}` captures ", hidden_ty),
hidden_region,
@@ -649,7 +652,8 @@ pub fn unexpected_hidden_region_diagnostic(
// If the `region_scope_tree` is available, this is being
// invoked from the "region inferencer error". We can at
// least report a really cryptic error for now.
tcx.note_and_explain_region(
note_and_explain_region(
tcx,
region_scope_tree,
&mut err,
&format!("hidden type `{}` captures ", hidden_ty),
@@ -1130,7 +1134,7 @@ fn fold_opaque_ty(
debug!("instantiate_opaque_types: bounds={:?}", bounds);
let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
let required_region_bounds = required_region_bounds(tcx, ty, bounds.predicates.clone());
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
// Make sure that we are in fact defining the *entire* type
@@ -1225,3 +1229,67 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir
);
res
}
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
/// parameter `erased_self_ty` must be supplied to indicate what type
/// has been used to represent `Self` in the predicates
/// themselves. This should really be a unique type; `FreshTy(0)` is a
/// popular choice.
///
/// N.B., in some cases, particularly around higher-ranked bounds,
/// this function returns a kind of conservative approximation.
/// That is, all regions returned by this function are definitely
/// required, but there may be other region bounds that are not
/// returned, as well as requirements like `for<'a> T: 'a`.
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
//
// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
// what this code should accept.
crate fn required_region_bounds(
tcx: TyCtxt<'tcx>,
erased_self_ty: Ty<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>,
) -> Vec<ty::Region<'tcx>> {
debug!(
"required_region_bounds(erased_self_ty={:?}, predicates={:?})",
erased_self_ty, predicates
);
assert!(!erased_self_ty.has_escaping_bound_vars());
traits::elaborate_predicates(tcx, predicates)
.filter_map(|predicate| {
match predicate {
ty::Predicate::Projection(..)
| ty::Predicate::Trait(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::ConstEvaluatable(..) => None,
ty::Predicate::TypeOutlives(predicate) => {
// Search for a bound of the form `erased_self_ty
// : 'a`, but be wary of something like `for<'a>
// erased_self_ty : 'a` (we interpret a
// higher-ranked bound like that as 'static,
// though at present the code in `fulfill.rs`
// considers such bounds to be unsatisfiable, so
// it's kind of a moot point since you could never
// construct such an object, but this seems
// correct even if that code changes).
let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
if t == &erased_self_ty && !r.has_escaping_bound_vars() {
Some(*r)
} else {
None
}
}
}
})
.collect()
}
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::infer::outlives::free_region_map::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
use crate::traits::query::outlives_bounds::{self, OutlivesBound};
use crate::ty::free_region_map::FreeRegionMap;
use crate::ty::{self, Ty};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-1
View File
@@ -1,6 +1,5 @@
//! Various code related to computing outlives relations.
pub mod env;
pub mod free_region_map;
pub mod obligations;
pub mod verify;
+1 -1
View File
@@ -3,8 +3,8 @@
//! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type,
//! and use that to decide when one free region outlives another, and so forth.
use crate::infer::outlives::free_region_map::{FreeRegionMap, FreeRegionRelations};
use crate::middle::region;
use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations};
use crate::ty::{self, Region, TyCtxt};
use rustc_hir::def_id::DefId;
+26 -28
View File
@@ -245,35 +245,35 @@ pub enum EvalResult {
Unmarked,
}
impl<'tcx> TyCtxt<'tcx> {
// See issue #38412.
fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
// Check if `def_id` is a trait method.
match self.def_kind(def_id) {
Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container {
// Trait methods do not declare visibility (even
// for visibility info in cstore). Use containing
// trait instead, so methods of `pub` traits are
// themselves considered `pub`.
def_id = trait_def_id;
}
// See issue #38412.
fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool {
// Check if `def_id` is a trait method.
match tcx.def_kind(def_id) {
Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container {
// Trait methods do not declare visibility (even
// for visibility info in cstore). Use containing
// trait instead, so methods of `pub` traits are
// themselves considered `pub`.
def_id = trait_def_id;
}
_ => {}
}
let visibility = self.visibility(def_id);
match visibility {
// Must check stability for `pub` items.
ty::Visibility::Public => false,
// These are not visible outside crate; therefore
// stability markers are irrelevant, if even present.
ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
}
_ => {}
}
let visibility = tcx.visibility(def_id);
match visibility {
// Must check stability for `pub` items.
ty::Visibility::Public => false,
// These are not visible outside crate; therefore
// stability markers are irrelevant, if even present.
ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
}
}
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates the stability of an item.
///
/// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
@@ -338,7 +338,7 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
}
// Issue #38412: private items lack stability markers.
if self.skip_stability_check_due_to_privacy(def_id) {
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
}
@@ -402,9 +402,7 @@ pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
}
}
}
}
impl<'tcx> TyCtxt<'tcx> {
pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
}
-26
View File
@@ -8,7 +8,6 @@
FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
};
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, TyCtxt};
/// Attempts to resolve an obligation to a vtable. The result is
@@ -76,31 +75,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
})
}
impl<'tcx> TyCtxt<'tcx> {
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then normalizing any associated
/// types.
pub fn subst_and_normalize_erasing_regions<T>(
self,
param_substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> T
where
T: TypeFoldable<'tcx>,
{
debug!(
"subst_and_normalize_erasing_regions(\
param_substs={:?}, \
value={:?}, \
param_env={:?})",
param_substs, value, param_env,
);
let substituted = value.subst(self, param_substs);
self.normalize_erasing_regions(param_env, substituted)
}
}
// # Global Cache
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+57 -58
View File
@@ -11,6 +11,7 @@
use crate::infer::{self, InferCtxt};
use crate::mir::interpret::ErrorHandled;
use crate::session::DiagnosticMessageId;
use crate::traits::object_safety_violations;
use crate::ty::error::ExpectedFound;
use crate::ty::fast_reject;
use crate::ty::fold::TypeFolder;
@@ -915,8 +916,8 @@ pub fn report_selection_error(
}
ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = self.tcx.object_safety_violations(trait_def_id);
self.tcx.report_object_safety_error(span, trait_def_id, violations)
let violations = object_safety_violations(self.tcx, trait_def_id);
report_object_safety_error(self.tcx, span, trait_def_id, violations)
}
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -1079,8 +1080,8 @@ pub fn report_selection_error(
}
TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
self.tcx.report_object_safety_error(span, did, violations)
let violations = object_safety_violations(self.tcx, did);
report_object_safety_error(self.tcx, span, did, violations)
}
// already reported in the query
@@ -1945,64 +1946,62 @@ fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>)
}
}
impl<'tcx> TyCtxt<'tcx> {
pub fn recursive_type_with_infinite_size_error(
self,
type_def_id: DefId,
) -> DiagnosticBuilder<'tcx> {
assert!(type_def_id.is_local());
let span = self.hir().span_if_local(type_def_id).unwrap();
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(
self.sess,
span,
E0072,
"recursive type `{}` has infinite size",
self.def_path_str(type_def_id)
);
err.span_label(span, "recursive type has infinite size");
err.help(&format!(
"insert indirection (e.g., a `Box`, `Rc`, or `&`) \
pub fn recursive_type_with_infinite_size_error(
tcx: TyCtxt<'tcx>,
type_def_id: DefId,
) -> DiagnosticBuilder<'tcx> {
assert!(type_def_id.is_local());
let span = tcx.hir().span_if_local(type_def_id).unwrap();
let span = tcx.sess.source_map().def_span(span);
let mut err = struct_span_err!(
tcx.sess,
span,
E0072,
"recursive type `{}` has infinite size",
tcx.def_path_str(type_def_id)
);
err.span_label(span, "recursive type has infinite size");
err.help(&format!(
"insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
self.def_path_str(type_def_id)
));
err
tcx.def_path_str(type_def_id)
));
err
}
pub fn report_object_safety_error(
tcx: TyCtxt<'tcx>,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
) -> DiagnosticBuilder<'tcx> {
let trait_str = tcx.def_path_str(trait_def_id);
let span = tcx.sess.source_map().def_span(span);
let mut err = struct_span_err!(
tcx.sess,
span,
E0038,
"the trait `{}` cannot be made into an object",
trait_str
);
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
let mut reported_violations = FxHashSet::default();
for violation in violations {
if reported_violations.insert(violation.clone()) {
match violation.span() {
Some(span) => err.span_label(span, violation.error_msg()),
None => err.note(&violation.error_msg()),
};
}
}
pub fn report_object_safety_error(
self,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
) -> DiagnosticBuilder<'tcx> {
let trait_str = self.def_path_str(trait_def_id);
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(
self.sess,
span,
E0038,
"the trait `{}` cannot be made into an object",
trait_str
);
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
let mut reported_violations = FxHashSet::default();
for violation in violations {
if reported_violations.insert(violation.clone()) {
match violation.span() {
Some(span) => err.span_label(span, violation.error_msg()),
None => err.note(&violation.error_msg()),
};
}
}
if self.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
err.cancel();
}
err
if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
err.cancel();
}
err
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+2 -1
View File
@@ -9,6 +9,7 @@
use super::engine::{TraitEngine, TraitEngineExt};
use super::project;
use super::select::SelectionContext;
use super::wf;
use super::CodeAmbiguity;
use super::CodeProjectionError;
use super::CodeSelectionError;
@@ -461,7 +462,7 @@ fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
}
ty::Predicate::WellFormed(ty) => {
match ty::wf::obligations(
match wf::obligations(
self.selcx.infcx(),
obligation.param_env,
obligation.cause.body_id,
+202
View File
@@ -0,0 +1,202 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
use crate::middle::lang_items;
use crate::traits::{self, ObligationCause};
use crate::ty::util::NeedsDrop;
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_hir as hir;
use rustc_span::DUMMY_SP;
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
InfrigingFields(Vec<&'tcx ty::FieldDef>),
NotAnAdt,
HasDestructor,
}
pub fn can_type_implement_copy(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
let (adt, substs) = match self_type.kind {
// These types used to have a builtin impl.
// Now libcore provides that impl.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
};
let mut infringing = Vec::new();
for variant in &adt.variants {
for field in &variant.fields {
let ty = field.ty(tcx, substs);
if ty.references_error() {
continue;
}
let span = tcx.def_span(field.did);
let cause = ObligationCause { span, ..ObligationCause::dummy() };
let ctx = traits::FulfillmentContext::new();
match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
infringing.push(field);
}
}
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
}
};
}
}
if !infringing.is_empty() {
return Err(CopyImplementationError::InfrigingFields(infringing));
}
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
Ok(())
})
}
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
}
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
}
fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
}
fn is_item_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
item: lang_items::LangItem,
) -> bool {
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(item, None);
tcx.infer_ctxt().enter(|infcx| {
traits::type_known_to_meet_bound_modulo_regions(
&infcx,
param_env,
ty,
trait_def_id,
DUMMY_SP,
)
})
}
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
let (param_env, ty) = query.into_parts();
let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
assert!(!ty.needs_infer());
NeedsDrop(match ty.kind {
// Fast-path for primitive types
ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
| ty::Bool
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Never
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Char
| ty::GeneratorWitness(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str => false,
// Foreign types can never have destructors
ty::Foreign(..) => false,
// `ManuallyDrop` doesn't have a destructor regardless of field types.
ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
// Issue #22536: We first query `is_copy_modulo_regions`. It sees a
// normalized version of the type, and therefore will definitely
// know whether the type implements Copy (and thus needs no
// cleanup/drop/zeroing) ...
_ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
// ... (issue #22536 continued) but as an optimization, still use
// prior logic of asking for the structural "may drop".
// FIXME(#22815): Note that this is a conservative heuristic;
// it may report that the type "may drop" when actual type does
// not actually have a destructor associated with it. But since
// the type absolutely did not have the `Copy` bound attached
// (see above), it is sound to treat it as having a destructor.
// User destructors are the only way to have concrete drop types.
ty::Adt(def, _) if def.has_dtor(tcx) => true,
// Can refer to a type which may drop.
// FIXME(eddyb) check this against a ParamEnv.
ty::Dynamic(..)
| ty::Projection(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Opaque(..)
| ty::Infer(_)
| ty::Error => true,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
// Zero-length arrays never contain anything to drop.
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
// Structural recursion.
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
ty::Closure(def_id, ref substs) => {
substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
}
// Pessimistically assume that all generators will require destructors
// as we don't know if a destructor is a noop or not until after the MIR
// state transformation pass
ty::Generator(..) => true,
ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
// unions don't have destructors because of the child types,
// only if they manually implement `Drop` (handled above).
ty::Adt(def, _) if def.is_union() => false,
ty::Adt(def, substs) => def
.variants
.iter()
.any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
})
}
pub fn provide(providers: &mut ty::query::Providers<'_>) {
*providers = ty::query::Providers {
is_copy_raw,
is_sized_raw,
is_freeze_raw,
needs_drop_raw,
..*providers
};
}
+15 -1
View File
@@ -10,6 +10,7 @@
mod engine;
pub mod error_reporting;
mod fulfill;
pub mod misc;
mod object_safety;
mod on_unimplemented;
mod project;
@@ -17,7 +18,9 @@
mod select;
mod specialize;
mod structural_impls;
mod structural_match;
mod util;
pub mod wf;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, SuppressRegionErrors};
@@ -47,6 +50,9 @@
pub use self::coherence::{OrphanCheckErr, OverlapResult};
pub use self::engine::{TraitEngine, TraitEngineExt};
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::object_safety_violations;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
@@ -59,8 +65,15 @@
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_match::type_marked_structural;
pub use self::structural_match::NonStructuralMatchTy;
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
predicate_for_trait_def, upcast_choices,
};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
};
@@ -1062,7 +1075,7 @@ fn vtable_methods<'tcx>(
let def_id = trait_method.def_id;
// Some methods cannot be called on an object; skip those.
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
debug!("vtable_methods: not vtable safe");
return None;
}
@@ -1231,6 +1244,7 @@ fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
}
pub fn provide(providers: &mut ty::query::Providers<'_>) {
misc::provide(providers);
*providers = ty::query::Providers {
is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
+569 -564
View File
@@ -108,614 +108,619 @@ pub enum MethodViolationCode {
UndispatchableReceiver,
}
impl<'tcx> TyCtxt<'tcx> {
/// Returns the object safety violations that affect
/// astconv -- currently, `Self` in supertraits. This is needed
/// because `object_safety_violations` can't be used during
/// type collection.
pub fn astconv_object_safety_violations(
self,
trait_def_id: DefId,
) -> Vec<ObjectSafetyViolation> {
debug_assert!(self.generics_of(trait_def_id).has_self);
let violations = traits::supertrait_def_ids(self, trait_def_id)
.filter(|&def_id| self.predicates_reference_self(def_id, true))
.map(|_| ObjectSafetyViolation::SupertraitSelf)
.collect();
/// Returns the object safety violations that affect
/// astconv -- currently, `Self` in supertraits. This is needed
/// because `object_safety_violations` can't be used during
/// type collection.
pub fn astconv_object_safety_violations(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> Vec<ObjectSafetyViolation> {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
let violations = traits::supertrait_def_ids(tcx, trait_def_id)
.filter(|&def_id| predicates_reference_self(tcx, def_id, true))
.map(|_| ObjectSafetyViolation::SupertraitSelf)
.collect();
debug!(
"astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
trait_def_id, violations
);
debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
violations
violations
}
pub fn object_safety_violations(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> Vec<ObjectSafetyViolation> {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("object_safety_violations: {:?}", trait_def_id);
traits::supertrait_def_ids(tcx, trait_def_id)
.flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
.collect()
}
/// We say a method is *vtable safe* if it can be invoked on a trait
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self: Sized` or
/// otherwise ensure that they cannot be used when `Self = Trait`.
pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self: Sized` bound cannot be called.
if generics_require_sized_self(tcx, method.def_id) {
return false;
}
pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
debug_assert!(self.generics_of(trait_def_id).has_self);
debug!("object_safety_violations: {:?}", trait_def_id);
traits::supertrait_def_ids(self, trait_def_id)
.flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
.collect()
match virtual_call_violation_for_method(tcx, trait_def_id, method) {
None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
Some(_) => false,
}
}
/// We say a method is *vtable safe* if it can be invoked on a trait
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self: Sized` or
/// otherwise ensure that they cannot be used when `Self = Trait`.
pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
debug_assert!(self.generics_of(trait_def_id).has_self);
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self: Sized` bound cannot be called.
if self.generics_require_sized_self(method.def_id) {
return false;
}
match self.virtual_call_violation_for_method(trait_def_id, method) {
None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
Some(_) => false,
}
}
fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
// Check methods for violations.
let mut violations: Vec<_> = self
.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssocKind::Method)
.filter_map(|item| {
self.object_safety_violation_for_method(trait_def_id, &item).map(|code| {
ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span)
})
})
.filter(|violation| {
if let ObjectSafetyViolation::Method(
_,
MethodViolationCode::WhereClauseReferencesSelf,
span,
) = violation
{
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span.
self.lint_node_note(
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
hir::CRATE_HIR_ID,
*span,
&format!(
"the trait `{}` cannot be made into an object",
self.def_path_str(trait_def_id)
),
&violation.error_msg(),
);
false
} else {
true
}
})
.collect();
// Check the trait itself.
if self.trait_has_sized_self(trait_def_id) {
violations.push(ObjectSafetyViolation::SizedSelf);
}
if self.predicates_reference_self(trait_def_id, false) {
violations.push(ObjectSafetyViolation::SupertraitSelf);
}
violations.extend(
self.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssocKind::Const)
.map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
);
debug!(
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
trait_def_id, violations
);
violations
}
fn predicates_reference_self(self, trait_def_id: DefId, supertraits_only: bool) -> bool {
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
let predicates = if supertraits_only {
self.super_predicates_of(trait_def_id)
} else {
self.predicates_of(trait_def_id)
};
let self_ty = self.types.self_param;
let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty);
predicates
.predicates
.iter()
.map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref))
.any(|predicate| {
match predicate {
ty::Predicate::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
data.skip_binder().input_types().skip(1).any(has_self_ty)
}
ty::Predicate::Projection(ref data) => {
// And similarly for projections. This should be redundant with
// the previous check because any projection should have a
// matching `Trait` predicate with the same inputs, but we do
// the check to be safe.
//
// Note that we *do* allow projection *outputs* to contain
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
// we just require the user to specify *both* outputs
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
data.skip_binder()
.projection_ty
.trait_ref(self)
.input_types()
.skip(1)
.any(has_self_ty)
}
ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::TypeOutlives(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => false,
}
})
}
fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
self.generics_require_sized_self(trait_def_id)
}
fn generics_require_sized_self(self, def_id: DefId) -> bool {
let sized_def_id = match self.lang_items().sized_trait() {
Some(def_id) => def_id,
None => {
return false; /* No Sized trait, can't require it! */
}
};
// Search for a predicate like `Self : Sized` amongst the trait bounds.
let predicates = self.predicates_of(def_id);
let predicates = predicates.instantiate_identity(self).predicates;
elaborate_predicates(self, predicates).any(|predicate| match predicate {
ty::Predicate::Trait(ref trait_pred) => {
trait_pred.def_id() == sized_def_id
&& trait_pred.skip_binder().self_ty().is_param(0)
}
ty::Predicate::Projection(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::TypeOutlives(..)
| ty::Predicate::ConstEvaluatable(..) => false,
fn object_safety_violations_for_trait(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> Vec<ObjectSafetyViolation> {
// Check methods for violations.
let mut violations: Vec<_> = tcx
.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssocKind::Method)
.filter_map(|item| {
object_safety_violation_for_method(tcx, trait_def_id, &item)
.map(|code| ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span))
})
}
/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method(
self,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
if self.generics_require_sized_self(method.def_id) {
return None;
}
self.virtual_call_violation_for_method(trait_def_id, method)
}
/// Returns `Some(_)` if this method cannot be called on a trait
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
fn virtual_call_violation_for_method(
self,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
// The method's first parameter must be named `self`
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
}
let sig = self.fn_sig(method.def_id);
for input_ty in &sig.skip_binder().inputs()[1..] {
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
.filter(|violation| {
if let ObjectSafetyViolation::Method(
_,
MethodViolationCode::WhereClauseReferencesSelf,
span,
) = violation
{
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span.
tcx.lint_node_note(
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
hir::CRATE_HIR_ID,
*span,
&format!(
"the trait `{}` cannot be made into an object",
tcx.def_path_str(trait_def_id)
),
&violation.error_msg(),
);
false
} else {
true
}
})
.collect();
// Check the trait itself.
if trait_has_sized_self(tcx, trait_def_id) {
violations.push(ObjectSafetyViolation::SizedSelf);
}
if predicates_reference_self(tcx, trait_def_id, false) {
violations.push(ObjectSafetyViolation::SupertraitSelf);
}
violations.extend(
tcx.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssocKind::Const)
.map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
);
debug!(
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
trait_def_id, violations
);
violations
}
fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool {
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
let predicates = if supertraits_only {
tcx.super_predicates_of(trait_def_id)
} else {
tcx.predicates_of(trait_def_id)
};
let self_ty = tcx.types.self_param;
let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty);
predicates
.predicates
.iter()
.map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
.any(|predicate| {
match predicate {
ty::Predicate::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
data.skip_binder().input_types().skip(1).any(has_self_ty)
}
ty::Predicate::Projection(ref data) => {
// And similarly for projections. This should be redundant with
// the previous check because any projection should have a
// matching `Trait` predicate with the same inputs, but we do
// the check to be safe.
//
// Note that we *do* allow projection *outputs* to contain
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
// we just require the user to specify *both* outputs
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
data.skip_binder()
.projection_ty
.trait_ref(tcx)
.input_types()
.skip(1)
.any(has_self_ty)
}
ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::TypeOutlives(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => false,
}
})
}
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
generics_require_sized_self(tcx, trait_def_id)
}
fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let sized_def_id = match tcx.lang_items().sized_trait() {
Some(def_id) => def_id,
None => {
return false; /* No Sized trait, can't require it! */
}
if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
};
// Search for a predicate like `Self : Sized` amongst the trait bounds.
let predicates = tcx.predicates_of(def_id);
let predicates = predicates.instantiate_identity(tcx).predicates;
elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
ty::Predicate::Trait(ref trait_pred) => {
trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
}
ty::Predicate::Projection(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::TypeOutlives(..)
| ty::Predicate::ConstEvaluatable(..) => false,
})
}
/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
if generics_require_sized_self(tcx, method.def_id) {
return None;
}
virtual_call_violation_for_method(tcx, trait_def_id, method)
}
/// Returns `Some(_)` if this method cannot be called on a trait
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
fn virtual_call_violation_for_method<'tcx>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
// The method's first parameter must be named `self`
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
}
let sig = tcx.fn_sig(method.def_id);
for input_ty in &sig.skip_binder().inputs()[1..] {
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
}
// We can't monomorphize things like `fn foo<A>(...)`.
let own_counts = self.generics_of(method.def_id).own_counts();
if own_counts.types + own_counts.consts != 0 {
return Some(MethodViolationCode::Generic);
}
if self
.predicates_of(method.def_id)
.predicates
.iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.cloned()
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
.collect::<Vec<_>>()
// Do a shallow visit so that `contains_illegal_self_type_reference`
// may apply it's custom visiting.
.visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t))
{
return Some(MethodViolationCode::WhereClauseReferencesSelf);
}
let receiver_ty =
self.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
// However, this is already considered object-safe. We allow it as a special case here.
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
if receiver_ty != self.types.self_param {
if !self.receiver_is_dispatchable(method, receiver_ty) {
return Some(MethodViolationCode::UndispatchableReceiver);
} else {
// Do sanity check to make sure the receiver actually has the layout of a pointer.
use crate::ty::layout::Abi;
let param_env = self.param_env(method.def_id);
let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
match self.layout_of(param_env.and(ty)) {
Ok(layout) => &layout.abi,
Err(err) => {
bug!("error: {}\n while computing layout for type {:?}", err, ty)
}
}
};
// e.g., `Rc<()>`
let unit_receiver_ty =
self.receiver_for_self_ty(receiver_ty, self.mk_unit(), method.def_id);
match abi_of_ty(unit_receiver_ty) {
&Abi::Scalar(..) => (),
abi => {
self.sess.delay_span_bug(
self.def_span(method.def_id),
&format!(
"receiver when `Self = ()` should have a Scalar ABI; found {:?}",
abi
),
);
}
}
let trait_object_ty =
self.object_ty_for_trait(trait_def_id, self.mk_region(ty::ReStatic));
// e.g., `Rc<dyn Trait>`
let trait_object_receiver =
self.receiver_for_self_ty(receiver_ty, trait_object_ty, method.def_id);
match abi_of_ty(trait_object_receiver) {
&Abi::ScalarPair(..) => (),
abi => {
self.sess.delay_span_bug(
self.def_span(method.def_id),
&format!(
"receiver when `Self = {}` should have a ScalarPair ABI; \
found {:?}",
trait_object_ty, abi
),
);
}
}
}
}
None
}
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) {
return Some(MethodViolationCode::ReferencesSelf);
}
/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
fn receiver_for_self_ty(
self,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
method_def_id: DefId,
) -> Ty<'tcx> {
debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
let substs = InternalSubsts::for_item(self, method_def_id, |param, _| {
if param.index == 0 { self_ty.into() } else { self.mk_param_from_def(param) }
});
let result = receiver_ty.subst(self, substs);
debug!(
"receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
receiver_ty, self_ty, method_def_id, result
);
result
// We can't monomorphize things like `fn foo<A>(...)`.
let own_counts = tcx.generics_of(method.def_id).own_counts();
if own_counts.types + own_counts.consts != 0 {
return Some(MethodViolationCode::Generic);
}
/// Creates the object type for the current trait. For example,
/// if the current trait is `Deref`, then this will be
/// `dyn Deref<Target = Self::Target> + 'static`.
fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> {
debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
let trait_ref = ty::TraitRef::identity(self, trait_def_id);
let trait_predicate = ty::ExistentialPredicate::Trait(
ty::ExistentialTraitRef::erase_self_ty(self, trait_ref),
);
let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref))
.flat_map(|super_trait_ref| {
self.associated_items(super_trait_ref.def_id())
.map(move |item| (super_trait_ref, item))
})
.filter(|(_, item)| item.kind == ty::AssocKind::Type)
.collect::<Vec<_>>();
// existential predicates need to be in a specific order
associated_types.sort_by_cached_key(|(_, item)| self.def_path_hash(item.def_id));
let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
// We *can* get bound lifetimes here in cases like
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
//
// binder moved to (*)...
let super_trait_ref = super_trait_ref.skip_binder();
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
ty: self.mk_projection(item.def_id, super_trait_ref.substs),
item_def_id: item.def_id,
substs: super_trait_ref.substs,
})
});
let existential_predicates = self
.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
let object_ty = self.mk_dynamic(
// (*) ... binder re-introduced here
ty::Binder::bind(existential_predicates),
lifetime,
);
debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
object_ty
if tcx
.predicates_of(method.def_id)
.predicates
.iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.cloned()
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
.collect::<Vec<_>>()
// Do a shallow visit so that `contains_illegal_self_type_reference`
// may apply it's custom visiting.
.visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t))
{
return Some(MethodViolationCode::WhereClauseReferencesSelf);
}
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
/// in the following way:
/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
/// - require the following bound:
///
/// ```
/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
/// ```
///
/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
/// (substitution notation).
///
/// Some examples of receiver types and their required obligation:
/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
///
/// The only case where the receiver is not dispatchable, but is still a valid receiver
/// type (just not object-safe), is when there is more than one level of pointer indirection.
/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
/// contained by the trait object, because the object that needs to be coerced is behind
/// a pointer.
///
/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
/// Instead, we fudge a little by introducing a new type parameter `U` such that
/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
/// Written as a chalk-style query:
///
/// forall (U: Trait + ?Sized) {
/// if (Self: Unsize<U>) {
/// Receiver: DispatchFromDyn<Receiver[Self => U]>
/// }
/// }
///
/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
//
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
// `self: Wrapper<Self>`.
#[allow(dead_code)]
fn receiver_is_dispatchable(self, method: &ty::AssocItem, receiver_ty: Ty<'tcx>) -> bool {
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
let receiver_ty =
tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
let traits =
(self.lang_items().unsize_trait(), self.lang_items().dispatch_from_dyn_trait());
let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
(u, cu)
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
// However, this is already considered object-safe. We allow it as a special case here.
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
if receiver_ty != tcx.types.self_param {
if !receiver_is_dispatchable(tcx, method, receiver_ty) {
return Some(MethodViolationCode::UndispatchableReceiver);
} else {
debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
return false;
};
// Do sanity check to make sure the receiver actually has the layout of a pointer.
// the type `U` in the query
// use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
// FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
// replace this with `dyn Trait`
let unsized_self_ty: Ty<'tcx> =
self.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
use crate::ty::layout::Abi;
// `Receiver[Self => U]`
let unsized_receiver_ty =
self.receiver_for_self_ty(receiver_ty, unsized_self_ty, method.def_id);
let param_env = tcx.param_env(method.def_id);
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
// `U: ?Sized` is already implied here
let param_env = {
let mut param_env = self.param_env(method.def_id);
// Self: Unsize<U>
let unsize_predicate = ty::TraitRef {
def_id: unsize_did,
substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]),
}
.to_predicate();
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
let substs =
InternalSubsts::for_item(self, method.container.assert_trait(), |param, _| {
if param.index == 0 {
unsized_self_ty.into()
} else {
self.mk_param_from_def(param)
}
});
ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
match tcx.layout_of(param_env.and(ty)) {
Ok(layout) => &layout.abi,
Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty),
}
};
let caller_bounds: Vec<Predicate<'tcx>> = param_env
.caller_bounds
.iter()
.cloned()
.chain(iter::once(unsize_predicate))
.chain(iter::once(trait_predicate))
.collect();
// e.g., `Rc<()>`
let unit_receiver_ty =
receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
param_env.caller_bounds = self.intern_predicates(&caller_bounds);
param_env
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let obligation = {
let predicate = ty::TraitRef {
def_id: dispatch_from_dyn_did,
substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
match abi_of_ty(unit_receiver_ty) {
&Abi::Scalar(..) => (),
abi => {
tcx.sess.delay_span_bug(
tcx.def_span(method.def_id),
&format!(
"receiver when `Self = ()` should have a Scalar ABI; found {:?}",
abi
),
);
}
}
.to_predicate();
Obligation::new(ObligationCause::dummy(), param_env, predicate)
};
let trait_object_ty =
object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic));
self.infer_ctxt().enter(|ref infcx| {
// the receiver is dispatchable iff the obligation holds
infcx.predicate_must_hold_modulo_regions(&obligation)
// e.g., `Rc<dyn Trait>`
let trait_object_receiver =
receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
match abi_of_ty(trait_object_receiver) {
&Abi::ScalarPair(..) => (),
abi => {
tcx.sess.delay_span_bug(
tcx.def_span(method.def_id),
&format!(
"receiver when `Self = {}` should have a ScalarPair ABI; \
found {:?}",
trait_object_ty, abi
),
);
}
}
}
}
None
}
/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
fn receiver_for_self_ty<'tcx>(
tcx: TyCtxt<'tcx>,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
method_def_id: DefId,
) -> Ty<'tcx> {
debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
});
let result = receiver_ty.subst(tcx, substs);
debug!(
"receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
receiver_ty, self_ty, method_def_id, result
);
result
}
/// Creates the object type for the current trait. For example,
/// if the current trait is `Deref`, then this will be
/// `dyn Deref<Target = Self::Target> + 'static`.
fn object_ty_for_trait<'tcx>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
lifetime: ty::Region<'tcx>,
) -> Ty<'tcx> {
debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
let trait_predicate =
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
.flat_map(|super_trait_ref| {
tcx.associated_items(super_trait_ref.def_id()).map(move |item| (super_trait_ref, item))
})
}
.filter(|(_, item)| item.kind == ty::AssocKind::Type)
.collect::<Vec<_>>();
fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) -> bool {
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
// exception: it is ok to reference `Self` in order to access
// an associated type of the current trait, since we retain
// the value of those associated types in the object type
// itself.
// existential predicates need to be in a specific order
associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
// We *can* get bound lifetimes here in cases like
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
//
// ```rust
// trait SuperTrait {
// type X;
// }
//
// trait Trait : SuperTrait {
// type Y;
// fn foo(&self, x: Self) // bad
// fn foo(&self) -> Self // bad
// fn foo(&self) -> Option<Self> // bad
// fn foo(&self) -> Self::Y // OK, desugars to next example
// fn foo(&self) -> <Self as Trait>::Y // OK
// fn foo(&self) -> Self::X // OK, desugars to next example
// fn foo(&self) -> <Self as SuperTrait>::X // OK
// }
// ```
//
// However, it is not as simple as allowing `Self` in a projected
// type, because there are illegal ways to use `Self` as well:
//
// ```rust
// trait Trait : SuperTrait {
// ...
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
// }
// ```
//
// Here we will not have the type of `X` recorded in the
// object type, and we cannot resolve `Self as SomeOtherTrait`
// without knowing what `Self` is.
// binder moved to (*)...
let super_trait_ref = super_trait_ref.skip_binder();
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
item_def_id: item.def_id,
substs: super_trait_ref.substs,
})
});
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
let mut error = false;
let self_ty = self.types.self_param;
ty.maybe_walk(|ty| {
match ty.kind {
ty::Param(_) => {
if ty == self_ty {
error = true;
}
let existential_predicates =
tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
false // no contained types to walk
}
let object_ty = tcx.mk_dynamic(
// (*) ... binder re-introduced here
ty::Binder::bind(existential_predicates),
lifetime,
);
ty::Projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
// Compute supertraits of current trait lazily.
if supertraits.is_none() {
let trait_ref =
ty::Binder::bind(ty::TraitRef::identity(self, trait_def_id));
supertraits = Some(traits::supertraits(self, trait_ref).collect());
}
object_ty
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let projection_trait_ref = ty::Binder::bind(data.trait_ref(self));
let is_supertrait_of_current_trait =
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
/// in the following way:
/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
/// - require the following bound:
///
/// ```
/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
/// ```
///
/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
/// (substitution notation).
///
/// Some examples of receiver types and their required obligation:
/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
///
/// The only case where the receiver is not dispatchable, but is still a valid receiver
/// type (just not object-safe), is when there is more than one level of pointer indirection.
/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
/// contained by the trait object, because the object that needs to be coerced is behind
/// a pointer.
///
/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
/// Instead, we fudge a little by introducing a new type parameter `U` such that
/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
/// Written as a chalk-style query:
///
/// forall (U: Trait + ?Sized) {
/// if (Self: Unsize<U>) {
/// Receiver: DispatchFromDyn<Receiver[Self => U]>
/// }
/// }
///
/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
//
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
// `self: Wrapper<Self>`.
#[allow(dead_code)]
fn receiver_is_dispatchable<'tcx>(
tcx: TyCtxt<'tcx>,
method: &ty::AssocItem,
receiver_ty: Ty<'tcx>,
) -> bool {
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
if is_supertrait_of_current_trait {
false // do not walk contained types, do not report error, do collect $200
let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
(u, cu)
} else {
debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
return false;
};
// the type `U` in the query
// use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
// FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
// replace this with `dyn Trait`
let unsized_self_ty: Ty<'tcx> =
tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
// `Receiver[Self => U]`
let unsized_receiver_ty =
receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
// `U: ?Sized` is already implied here
let param_env = {
let mut param_env = tcx.param_env(method.def_id);
// Self: Unsize<U>
let unsize_predicate = ty::TraitRef {
def_id: unsize_did,
substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
}
.to_predicate();
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
let substs =
InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
if param.index == 0 {
unsized_self_ty.into()
} else {
true // DO walk contained types, POSSIBLY reporting an error
tcx.mk_param_from_def(param)
}
});
ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
};
let caller_bounds: Vec<Predicate<'tcx>> = param_env
.caller_bounds
.iter()
.cloned()
.chain(iter::once(unsize_predicate))
.chain(iter::once(trait_predicate))
.collect();
param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);
param_env
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let obligation = {
let predicate = ty::TraitRef {
def_id: dispatch_from_dyn_did,
substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
}
.to_predicate();
Obligation::new(ObligationCause::dummy(), param_env, predicate)
};
tcx.infer_ctxt().enter(|ref infcx| {
// the receiver is dispatchable iff the obligation holds
infcx.predicate_must_hold_modulo_regions(&obligation)
})
}
fn contains_illegal_self_type_reference<'tcx>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
ty: Ty<'tcx>,
) -> bool {
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
// exception: it is ok to reference `Self` in order to access
// an associated type of the current trait, since we retain
// the value of those associated types in the object type
// itself.
//
// ```rust
// trait SuperTrait {
// type X;
// }
//
// trait Trait : SuperTrait {
// type Y;
// fn foo(&self, x: Self) // bad
// fn foo(&self) -> Self // bad
// fn foo(&self) -> Option<Self> // bad
// fn foo(&self) -> Self::Y // OK, desugars to next example
// fn foo(&self) -> <Self as Trait>::Y // OK
// fn foo(&self) -> Self::X // OK, desugars to next example
// fn foo(&self) -> <Self as SuperTrait>::X // OK
// }
// ```
//
// However, it is not as simple as allowing `Self` in a projected
// type, because there are illegal ways to use `Self` as well:
//
// ```rust
// trait Trait : SuperTrait {
// ...
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
// }
// ```
//
// Here we will not have the type of `X` recorded in the
// object type, and we cannot resolve `Self as SomeOtherTrait`
// without knowing what `Self` is.
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
let mut error = false;
let self_ty = tcx.types.self_param;
ty.maybe_walk(|ty| {
match ty.kind {
ty::Param(_) => {
if ty == self_ty {
error = true;
}
_ => true, // walk contained types, if any
false // no contained types to walk
}
});
error
}
ty::Projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazily.
if supertraits.is_none() {
let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
let is_supertrait_of_current_trait =
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
if is_supertrait_of_current_trait {
false // do not walk contained types, do not report error, do collect $200
} else {
true // DO walk contained types, POSSIBLY reporting an error
}
}
_ => true, // walk contained types, if any
}
});
error
}
pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
tcx.object_safety_violations(trait_def_id).is_empty()
object_safety_violations(tcx, trait_def_id).is_empty()
}
+39 -35
View File
@@ -1057,7 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default()
|| selcx.tcx().impl_is_default(node_item.node.def_id())
|| super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
};
// Only reveal a specializable default if we're past type-checking
@@ -1263,26 +1263,30 @@ fn confirm_generator_candidate<'cx, 'tcx>(
let gen_def_id = tcx.lang_items().gen_trait().unwrap();
let predicate = tcx
.generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), gen_sig)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
yield_ty
} else {
bug!()
};
let predicate = super::util::generator_trait_ref_and_outputs(
tcx,
gen_def_id,
obligation.predicate.self_ty(),
gen_sig,
)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
yield_ty
} else {
bug!()
};
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
ty: ty,
}
});
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
ty: ty,
}
});
confirm_param_env_candidate(selcx, obligation, predicate)
.with_addl_obligations(vtable.nested)
@@ -1349,21 +1353,21 @@ fn confirm_callable_candidate<'cx, 'tcx>(
// the `Output` associated type is declared on `FnOnce`
let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap();
let predicate = tcx
.closure_trait_ref_and_return_type(
fn_once_def_id,
obligation.predicate.self_ty(),
fn_sig,
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
Ident::with_dummy_span(FN_OUTPUT_NAME),
),
ty: ret_type,
});
let predicate = super::util::closure_trait_ref_and_return_type(
tcx,
fn_once_def_id,
obligation.predicate.self_ty(),
fn_sig,
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
Ident::with_dummy_span(FN_OUTPUT_NAME),
),
ty: ret_type,
});
confirm_param_env_candidate(selcx, obligation, predicate)
}
-1
View File
@@ -13,7 +13,6 @@
pub mod evaluate_obligation;
pub mod method_autoderef;
pub mod normalize;
pub mod normalize_erasing_regions;
pub mod outlives_bounds;
pub mod type_op;
+34 -30
View File
@@ -11,6 +11,8 @@
use super::project;
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
use super::util;
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
use super::wf;
use super::DerivedObligationCause;
use super::Selection;
use super::SelectionResult;
@@ -737,7 +739,7 @@ fn evaluate_predicate_recursively<'o>(
}
}
ty::Predicate::WellFormed(ty) => match ty::wf::obligations(
ty::Predicate::WellFormed(ty) => match wf::obligations(
self.infcx,
obligation.param_env,
obligation.cause.body_id,
@@ -1153,7 +1155,7 @@ fn insert_evaluation_cache(
/// to have a *lower* recursion_depth than the obligation used to create it.
/// Projection sub-obligations may be returned from the projection cache,
/// which results in obligations with an 'old' `recursion_depth`.
/// Additionally, methods like `ty::wf::obligations` and
/// Additionally, methods like `wf::obligations` and
/// `InferCtxt.subtype_predicate` produce subobligations without
/// taking in a 'parent' depth, causing the generated subobligations
/// to have a `recursion_depth` of `0`.
@@ -2651,7 +2653,8 @@ fn collect_predicates_for_types(
recursion_depth,
&skol_ty,
);
let skol_obligation = self.tcx().predicate_for_trait_def(
let skol_obligation = predicate_for_trait_def(
self.tcx(),
param_env,
cause.clone(),
trait_def_id,
@@ -2988,7 +2991,7 @@ fn confirm_object_candidate(
// we pass over, we sum up the set of number of vtable
// entries, so that we can compute the offset for the selected
// trait.
vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum();
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
}
VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
@@ -3003,15 +3006,14 @@ fn confirm_fn_pointer_candidate(
// Okay to skip binder; it is reintroduced below.
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let sig = self_ty.fn_sig(self.tcx());
let trait_ref = self
.tcx()
.closure_trait_ref_and_return_type(
obligation.predicate.def_id(),
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
)
.map_bound(|(trait_ref, _)| trait_ref);
let trait_ref = closure_trait_ref_and_return_type(
self.tcx(),
obligation.predicate.def_id(),
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
)
.map_bound(|(trait_ref, _)| trait_ref);
let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
self,
@@ -3381,7 +3383,8 @@ fn confirm_builtin_unsize_candidate(
nested.extend(obligations);
// Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
nested.push(tcx.predicate_for_trait_def(
nested.push(predicate_for_trait_def(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
@@ -3416,7 +3419,8 @@ fn confirm_builtin_unsize_candidate(
nested.extend(obligations);
// Construct the nested `T: Unsize<U>` predicate.
nested.push(tcx.predicate_for_trait_def(
nested.push(predicate_for_trait_def(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
@@ -3627,14 +3631,14 @@ fn closure_trait_ref_unnormalized(
// in fact unparameterized (or at least does not reference any
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
self.tcx()
.closure_trait_ref_and_return_type(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
closure_type,
util::TupleArgumentsFlag::No,
)
.map_bound(|(trait_ref, _)| trait_ref)
closure_trait_ref_and_return_type(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
closure_type,
util::TupleArgumentsFlag::No,
)
.map_bound(|(trait_ref, _)| trait_ref)
}
fn generator_trait_ref_unnormalized(
@@ -3651,13 +3655,13 @@ fn generator_trait_ref_unnormalized(
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
self.tcx()
.generator_trait_ref_and_outputs(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
gen_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref)
super::util::generator_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
gen_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref)
}
/// Returns the obligations that are implied by instantiating an
+105 -107
View File
@@ -548,125 +548,123 @@ pub fn predicate_for_trait_ref<'tcx>(
Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
}
impl<'tcx> TyCtxt<'tcx> {
pub fn predicate_for_trait_def(
self,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(self_ty, params) };
predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
pub fn predicate_for_trait_def(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
}
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
tcx: TyCtxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
if source_trait_ref.def_id() == target_trait_def_id {
return vec![source_trait_ref]; // Shortcut the most common case.
}
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
self,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
if source_trait_ref.def_id() == target_trait_def_id {
return vec![source_trait_ref]; // Shortcut the most common case.
supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}
/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
let mut entries = 0;
// Count number of methods and add them to the total offset.
// Skip over associated types and constants.
for trait_item in tcx.associated_items(trait_ref.def_id()) {
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
supertraits(self, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}
entries
}
/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
let mut entries = 0;
// Count number of methods and add them to the total offset.
// Skip over associated types and constants.
for trait_item in self.associated_items(trait_ref.def_id()) {
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
tcx: TyCtxt<'tcx>,
object: &super::VtableObjectData<'tcx, N>,
method_def_id: DefId,
) -> usize {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
// Skip over associated types and constants.
let mut entries = object.vtable_base;
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) {
if trait_item.def_id == method_def_id {
// The item with the ID we were given really ought to be a method.
assert_eq!(trait_item.kind, ty::AssocKind::Method);
return entries;
}
entries
}
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
self,
object: &super::VtableObjectData<'tcx, N>,
method_def_id: DefId,
) -> usize {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
// Skip over associated types and constants.
let mut entries = object.vtable_base;
for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
if trait_item.def_id == method_def_id {
// The item with the ID we were given really ought to be a method.
assert_eq!(trait_item.kind, ty::AssocKind::Method);
return entries;
}
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}
pub fn closure_trait_ref_and_return_type(
self,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => self.intern_tup(sig.skip_binder().inputs()),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
};
ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}
pub fn generator_trait_ref_and_outputs(
self,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
let trait_ref =
ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]) };
ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}
pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
match self.hir().as_local_hir_id(node_item_def_id) {
Some(hir_id) => {
let item = self.hir().expect_item(hir_id);
if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
defaultness.is_default()
} else {
false
}
}
None => self.impl_defaultness(node_item_def_id).is_default(),
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool {
assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id())
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}
pub fn closure_trait_ref_and_return_type(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
};
ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}
pub fn generator_trait_ref_and_outputs(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
let trait_ref =
ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) };
ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}
pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool {
match tcx.hir().as_local_hir_id(node_item_def_id) {
Some(hir_id) => {
let item = tcx.hir().expect_item(hir_id);
if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
defaultness.is_default()
} else {
false
}
}
None => tcx.impl_defaultness(node_item_def_id).is_default(),
}
}
pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id())
}
pub enum TupleArgumentsFlag {
Yes,
No,
@@ -1,3 +1,4 @@
use crate::infer::opaque_types::required_region_bounds;
use crate::infer::InferCtxt;
use crate::middle::lang_items;
use crate::traits::{self, AssocTypeBoundData};
@@ -514,7 +515,7 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
// of whatever returned this exact `impl Trait`.
// for named opaque `impl Trait` types we still need to check them
if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
let obligations = self.nominal_obligations(did, substs);
self.out.extend(obligations);
}
@@ -668,7 +669,7 @@ fn from_object_ty(
/// from the declarations of `SomeTrait`, `Send`, and friends -- if
/// they declare `trait SomeTrait : 'static`, for example, then
/// `'static` would appear in the list. The hard work is done by
/// `ty::required_region_bounds`, see that for more information.
/// `infer::required_region_bounds`, see that for more information.
pub fn object_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
@@ -689,7 +690,7 @@ pub fn object_region_bounds<'tcx>(
})
.collect();
tcx.required_region_bounds(open_ty, predicates)
required_region_bounds(tcx, open_ty, predicates)
}
/// Find the span of a generic bound affecting an associated type.
+1 -1
View File
@@ -8,7 +8,6 @@
use crate::hir::map::DefPathHash;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::infer::outlives::free_region_map::FreeRegionMap;
use crate::lint::{self, Lint};
use crate::middle;
use crate::middle::cstore::CrateStoreDyn;
@@ -26,6 +25,7 @@
use crate::session::Session;
use crate::traits;
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
use crate::ty::free_region_map::FreeRegionMap;
use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
use crate::ty::query;
use crate::ty::steal::Steal;
+2 -6
View File
@@ -96,15 +96,11 @@ pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
// ```
// forest.is_empty()
// ```
self.ty_inhabitedness_forest(ty).contains(self, module)
ty.uninhabited_from(self).contains(self, module)
}
pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
!self.ty_inhabitedness_forest(ty).is_empty()
}
fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
ty.uninhabited_from(self)
!ty.uninhabited_from(self).is_empty()
}
}
+1 -1
View File
@@ -411,7 +411,7 @@ fn resolve_associated_item<'tcx>(
substs: rcvr_substs,
}),
traits::VtableObject(ref data) => {
let index = tcx.get_vtable_index_of_object_method(data, def_id);
let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
}
traits::VtableBuiltin(..) => {
+2 -7
View File
@@ -87,10 +87,6 @@
pub use self::instance::{Instance, InstanceDef};
pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_match::type_marked_structural;
pub use self::structural_match::NonStructuralMatchTy;
pub use self::trait_def::TraitDef;
pub use self::query::queries;
@@ -107,8 +103,10 @@
pub mod fast_reject;
pub mod flags;
pub mod fold;
pub mod free_region_map;
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
pub mod outlives;
pub mod print;
pub mod query;
@@ -118,13 +116,11 @@
pub mod trait_def;
pub mod util;
pub mod walk;
pub mod wf;
mod context;
mod diagnostics;
mod instance;
mod structural_impls;
mod structural_match;
mod sty;
// Data types
@@ -3322,7 +3318,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
context::provide(providers);
erase_regions::provide(providers);
layout::provide(providers);
util::provide(providers);
constness::provide(providers);
*providers = ty::query::Providers {
asyncness,
@@ -8,6 +8,7 @@
//! within. (This underlying query is what is cached.)
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
impl<'tcx> TyCtxt<'tcx> {
@@ -60,6 +61,29 @@ pub fn normalize_erasing_late_bound_regions<T>(
let value = self.erase_late_bound_regions(value);
self.normalize_erasing_regions(param_env, value)
}
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then normalizing any associated
/// types.
pub fn subst_and_normalize_erasing_regions<T>(
self,
param_substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> T
where
T: TypeFoldable<'tcx>,
{
debug!(
"subst_and_normalize_erasing_regions(\
param_substs={:?}, \
value={:?}, \
param_env={:?})",
param_substs, value, param_env,
);
let substituted = value.subst(self, param_substs);
self.normalize_erasing_regions(param_env, substituted)
}
}
struct NormalizeAfterErasingRegionsFolder<'tcx> {
+23 -27
View File
@@ -48,32 +48,29 @@ pub enum Component<'tcx> {
impl<'tcx> TyCtxt<'tcx> {
/// Push onto `out` all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
pub fn push_outlives_components(
&self,
ty0: Ty<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
) {
self.compute_components(ty0, out);
pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
compute_components(self, ty0, out);
debug!("components({:?}) = {:?}", ty0, out);
}
}
fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
// in the `subtys` iterator (e.g., when encountering a
// projection).
match ty.kind {
fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
// in the `subtys` iterator (e.g., when encountering a
// projection).
match ty.kind {
ty::Closure(def_id, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys(def_id, *self) {
self.compute_components(upvar_ty, out);
for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
compute_components(tcx, upvar_ty, out);
}
}
ty::Generator(def_id, ref substs, _) => {
// Same as the closure case
for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) {
self.compute_components(upvar_ty, out);
for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) {
compute_components(tcx, upvar_ty, out);
}
// We ignore regions in the generator interior as we don't
@@ -110,7 +107,7 @@ pub fn push_outlives_components(
// fallback case: hard code
// OutlivesProjectionComponents. Continue walking
// through and constrain Pi.
let subcomponents = self.capture_components(ty);
let subcomponents = capture_components(tcx, ty);
out.push(Component::EscapingProjection(subcomponents));
}
}
@@ -159,20 +156,19 @@ pub fn push_outlives_components(
push_region_constraints(ty, out);
for subty in ty.walk_shallow() {
self.compute_components(subty, out);
compute_components(tcx, subty, out);
}
}
}
}
}
fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
let mut temp = smallvec![];
push_region_constraints(ty, &mut temp);
for subty in ty.walk_shallow() {
self.compute_components(subty, &mut temp);
}
temp.into_iter().collect()
fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
let mut temp = smallvec![];
push_region_constraints(ty, &mut temp);
for subty in ty.walk_shallow() {
compute_components(tcx, subty, &mut temp);
}
temp.into_iter().collect()
}
fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+19 -19
View File
@@ -1036,26 +1036,26 @@ pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self {
}
}
impl TyCtxt<'t> {
// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
// (but also some things just print a `DefId` generally so maybe we need this?)
fn guess_def_namespace(self, def_id: DefId) -> Namespace {
match self.def_key(def_id).disambiguated_data.data {
DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
Namespace::TypeNS
}
DefPathData::ValueNs(..)
| DefPathData::AnonConst
| DefPathData::ClosureExpr
| DefPathData::Ctor => Namespace::ValueNS,
DefPathData::MacroNs(..) => Namespace::MacroNS,
_ => Namespace::TypeNS,
// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
// (but also some things just print a `DefId` generally so maybe we need this?)
fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
match tcx.def_key(def_id).disambiguated_data.data {
DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
Namespace::TypeNS
}
}
DefPathData::ValueNs(..)
| DefPathData::AnonConst
| DefPathData::ClosureExpr
| DefPathData::Ctor => Namespace::ValueNS,
DefPathData::MacroNs(..) => Namespace::MacroNS,
_ => Namespace::TypeNS,
}
}
impl TyCtxt<'t> {
/// Returns a string identifying this `DefId`. This string is
/// suitable for user output.
pub fn def_path_str(self, def_id: DefId) -> String {
@@ -1063,7 +1063,7 @@ pub fn def_path_str(self, def_id: DefId) -> String {
}
pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
let ns = self.guess_def_namespace(def_id);
let ns = guess_def_namespace(self, def_id);
debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
let mut s = String::new();
let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs);
+1 -262
View File
@@ -2,9 +2,7 @@
use crate::hir::map::DefPathData;
use crate::ich::NodeIdHashingMode;
use crate::middle::lang_items;
use crate::mir::interpret::{sign_extend, truncate};
use crate::traits::{self, ObligationCause};
use crate::ty::layout::{Integer, IntegerExt};
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
@@ -18,7 +16,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable;
use rustc_span::{Span, DUMMY_SP};
use rustc_span::Span;
use std::{cmp, fmt};
use syntax::ast;
use syntax::attr::{self, SignedInt, UnsignedInt};
@@ -122,13 +120,6 @@ fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option
}
}
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
InfrigingFields(Vec<&'tcx ty::FieldDef>),
NotAnAdt,
HasDestructor,
}
/// Describes whether a type is representable. For types that are not
/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
/// distinguish between types that are recursive with themselves and types that
@@ -144,65 +135,6 @@ pub enum Representability {
SelfRecursive(Vec<Span>),
}
impl<'tcx> ty::ParamEnv<'tcx> {
pub fn can_type_implement_copy(
self,
tcx: TyCtxt<'tcx>,
self_type: Ty<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
let (adt, substs) = match self_type.kind {
// These types used to have a builtin impl.
// Now libcore provides that impl.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
};
let mut infringing = Vec::new();
for variant in &adt.variants {
for field in &variant.fields {
let ty = field.ty(tcx, substs);
if ty.references_error() {
continue;
}
let span = tcx.def_span(field.did);
let cause = ObligationCause { span, ..ObligationCause::dummy() };
let ctx = traits::FulfillmentContext::new();
match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(self, ty, span) {
infringing.push(field);
}
}
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
}
};
}
}
if !infringing.is_empty() {
return Err(CopyImplementationError::InfrigingFields(infringing));
}
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
Ok(())
})
}
}
impl<'tcx> TyCtxt<'tcx> {
/// Creates a hash of the type `Ty` which will be the same no matter what crate
/// context it's calculated within. This is used by the `type_id` intrinsic.
@@ -393,70 +325,6 @@ pub fn struct_lockstep_tails_with_normalize(
(a, b)
}
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
/// parameter `erased_self_ty` must be supplied to indicate what type
/// has been used to represent `Self` in the predicates
/// themselves. This should really be a unique type; `FreshTy(0)` is a
/// popular choice.
///
/// N.B., in some cases, particularly around higher-ranked bounds,
/// this function returns a kind of conservative approximation.
/// That is, all regions returned by this function are definitely
/// required, but there may be other region bounds that are not
/// returned, as well as requirements like `for<'a> T: 'a`.
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
//
// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
// what this code should accept.
pub fn required_region_bounds(
self,
erased_self_ty: Ty<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>,
) -> Vec<ty::Region<'tcx>> {
debug!(
"required_region_bounds(erased_self_ty={:?}, predicates={:?})",
erased_self_ty, predicates
);
assert!(!erased_self_ty.has_escaping_bound_vars());
traits::elaborate_predicates(self, predicates)
.filter_map(|predicate| {
match predicate {
ty::Predicate::Projection(..)
| ty::Predicate::Trait(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::ConstEvaluatable(..) => None,
ty::Predicate::TypeOutlives(predicate) => {
// Search for a bound of the form `erased_self_ty
// : 'a`, but be wary of something like `for<'a>
// erased_self_ty : 'a` (we interpret a
// higher-ranked bound like that as 'static,
// though at present the code in `fulfill.rs`
// considers such bounds to be unsatisfiable, so
// it's kind of a moot point since you could never
// construct such an object, but this seems
// correct even if that code changes).
let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
if t == &erased_self_ty && !r.has_escaping_bound_vars() {
Some(*r)
} else {
None
}
}
}
})
.collect()
}
/// Calculate the destructor of a given type.
pub fn calculate_dtor(
self,
@@ -1006,128 +874,9 @@ pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
}
}
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
}
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
}
fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
}
fn is_item_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
item: lang_items::LangItem,
) -> bool {
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(item, None);
tcx.infer_ctxt().enter(|infcx| {
traits::type_known_to_meet_bound_modulo_regions(
&infcx,
param_env,
ty,
trait_def_id,
DUMMY_SP,
)
})
}
#[derive(Clone, HashStable)]
pub struct NeedsDrop(pub bool);
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
let (param_env, ty) = query.into_parts();
let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
assert!(!ty.needs_infer());
NeedsDrop(match ty.kind {
// Fast-path for primitive types
ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
| ty::Bool
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Never
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Char
| ty::GeneratorWitness(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str => false,
// Foreign types can never have destructors
ty::Foreign(..) => false,
// `ManuallyDrop` doesn't have a destructor regardless of field types.
ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
// Issue #22536: We first query `is_copy_modulo_regions`. It sees a
// normalized version of the type, and therefore will definitely
// know whether the type implements Copy (and thus needs no
// cleanup/drop/zeroing) ...
_ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
// ... (issue #22536 continued) but as an optimization, still use
// prior logic of asking for the structural "may drop".
// FIXME(#22815): Note that this is a conservative heuristic;
// it may report that the type "may drop" when actual type does
// not actually have a destructor associated with it. But since
// the type absolutely did not have the `Copy` bound attached
// (see above), it is sound to treat it as having a destructor.
// User destructors are the only way to have concrete drop types.
ty::Adt(def, _) if def.has_dtor(tcx) => true,
// Can refer to a type which may drop.
// FIXME(eddyb) check this against a ParamEnv.
ty::Dynamic(..)
| ty::Projection(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Opaque(..)
| ty::Infer(_)
| ty::Error => true,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
// Zero-length arrays never contain anything to drop.
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
// Structural recursion.
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
ty::Closure(def_id, ref substs) => {
substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
}
// Pessimistically assume that all generators will require destructors
// as we don't know if a destructor is a noop or not until after the MIR
// state transformation pass
ty::Generator(..) => true,
ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
// unions don't have destructors because of the child types,
// only if they manually implement `Drop` (handled above).
ty::Adt(def, _) if def.is_union() => false,
ty::Adt(def, substs) => def
.variants
.iter()
.any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
})
}
pub enum ExplicitSelf<'tcx> {
ByValue,
ByReference(ty::Region<'tcx>, hir::Mutability),
@@ -1176,13 +925,3 @@ pub fn determine<P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> ExplicitSelf<'tcx>
}
}
}
pub fn provide(providers: &mut ty::query::Providers<'_>) {
*providers = ty::query::Providers {
is_copy_raw,
is_sized_raw,
is_freeze_raw,
needs_drop_raw,
..*providers
};
}
+2 -1
View File
@@ -27,6 +27,7 @@
use lint::{LateContext, LintArray, LintContext};
use rustc::lint;
use rustc::lint::FutureIncompatibleInfo;
use rustc::traits::misc::can_type_implement_copy;
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Stability;
@@ -555,7 +556,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
return;
}
if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
cx.span_lint(
MISSING_COPY_IMPLEMENTATIONS,
item.span,
@@ -1,10 +1,10 @@
use rustc::infer::canonical::QueryRegionConstraints;
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
use rustc::infer::region_constraints::GenericKind;
use rustc::infer::InferCtxt;
use rustc::mir::ConstraintCategory;
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
use rustc::traits::query::type_op::{self, TypeOp};
use rustc::ty::free_region_map::FreeRegionRelations;
use rustc::ty::{self, RegionVid, Ty};
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_span::DUMMY_SP;
@@ -3,7 +3,8 @@
use rustc::infer::InferCtxt;
use rustc::lint;
use rustc::mir::Field;
use rustc::traits::{ObligationCause, PredicateObligation};
use rustc::traits::predicate_for_trait_def;
use rustc::traits::{self, ObligationCause, PredicateObligation};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
@@ -75,12 +76,12 @@ fn tcx(&self) -> TyCtxt<'tcx> {
fn search_for_structural_match_violation(
&self,
ty: Ty<'tcx>,
) -> Option<ty::NonStructuralMatchTy<'tcx>> {
ty::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
) -> Option<traits::NonStructuralMatchTy<'tcx>> {
traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
}
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
ty::type_marked_structural(self.id, self.span, &self.infcx, ty)
traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
}
fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
@@ -104,8 +105,8 @@ fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
);
if let Some(non_sm_ty) = structural {
let adt_def = match non_sm_ty {
ty::NonStructuralMatchTy::Adt(adt_def) => adt_def,
ty::NonStructuralMatchTy::Param => {
traits::NonStructuralMatchTy::Adt(adt_def) => adt_def,
traits::NonStructuralMatchTy::Param => {
bug!("use of constant whose type is a parameter inside a pattern")
}
};
@@ -129,7 +130,8 @@ fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
// not *yet* implement `PartialEq`. So for now we leave this here.
let ty_is_partial_eq: bool = {
let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
let obligation: PredicateObligation<'_> = self.tcx().predicate_for_trait_def(
let obligation: PredicateObligation<'_> = predicate_for_trait_def(
self.tcx(),
self.param_env,
ObligationCause::misc(self.span, self.id),
partial_eq_trait_id,
+2 -1
View File
@@ -6,6 +6,7 @@
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability::{DeprecationEntry, Index};
use rustc::session::Session;
use rustc::traits::misc::can_type_implement_copy;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -488,7 +489,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
.emit();
} else {
let param_env = self.tcx.param_env(def_id);
if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() {
feature_err(
&self.tcx.sess.parse_sess,
sym::untagged_unions,
@@ -5,11 +5,11 @@
use rustc::infer::InferCtxt;
use rustc::traits::query::outlives_bounds::OutlivesBound;
use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
use rustc::traits::wf;
use rustc::traits::FulfillmentContext;
use rustc::traits::{TraitEngine, TraitEngineExt};
use rustc::ty::outlives::Component;
use rustc::ty::query::Providers;
use rustc::ty::wf;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_hir as hir;
use rustc_span::source_map::DUMMY_SP;
+6 -3
View File
@@ -13,8 +13,10 @@
use rustc::hir::intravisit::Visitor;
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc::traits;
use rustc::traits::astconv_object_safety_violations;
use rustc::traits::error_reporting::report_object_safety_error;
use rustc::traits::wf::object_region_bounds;
use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
use rustc::ty::wf::object_region_bounds;
use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -1452,9 +1454,10 @@ fn conv_object_ty_poly_trait_ref(
// to avoid ICEs.
for item in &regular_traits {
let object_safety_violations =
tcx.astconv_object_safety_violations(item.trait_ref().def_id());
astconv_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
tcx.report_object_safety_error(
report_object_safety_error(
tcx,
span,
item.trait_ref().def_id(),
object_safety_violations,
+4 -2
View File
@@ -37,6 +37,8 @@
use rustc::middle::lang_items;
use rustc::session::Session;
use rustc::traits;
use rustc::traits::error_reporting::report_object_safety_error;
use rustc::traits::object_safety_violations;
use rustc::ty::adjustment::AllowTwoPhase;
use rustc::ty::cast::{CastKind, CastTy};
use rustc::ty::error::TypeError;
@@ -518,8 +520,8 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
}
fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
let violations = fcx.tcx.object_safety_violations(did);
let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
let violations = object_safety_violations(fcx.tcx, did);
let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
err.emit();
}
+2 -1
View File
@@ -544,7 +544,8 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
// and almost never more than 3. By using a SmallVec we avoid an
// allocation, at the (very small) cost of (occasionally) having to
// shift subsequent elements down when removing the front element.
let mut queue: SmallVec<[_; 4]> = smallvec![self.tcx.predicate_for_trait_def(
let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
self.tcx,
self.fcx.param_env,
cause,
coerce_unsized_did,
+1 -1
View File
@@ -596,7 +596,7 @@ fn upcast(
target_trait_def_id: DefId,
) -> ty::PolyTraitRef<'tcx> {
let upcast_trait_refs =
self.tcx.upcast_choices(source_trait_ref.clone(), target_trait_def_id);
traits::upcast_choices(self.tcx, source_trait_ref.clone(), target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc
if upcast_trait_refs.len() != 1 {
+5 -4
View File
@@ -100,6 +100,7 @@
use rustc::infer::{self, InferCtxt, InferOk, InferResult};
use rustc::middle::region;
use rustc::mir::interpret::ConstValue;
use rustc::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -1900,7 +1901,7 @@ fn check_specialization_validity<'tcx>(
match parent_item {
// Parent impl exists, and contains the parent item we're trying to specialize, but
// doesn't mark it `default`.
Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
Some(Err(parent_impl.def_id()))
}
@@ -1911,7 +1912,7 @@ fn check_specialization_validity<'tcx>(
// grandparent. In that case, if parent is a `default impl`, inherited items use the
// "defaultness" from the grandparent, else they are final.
None => {
if tcx.impl_is_default(parent_impl.def_id()) {
if traits::impl_is_default(tcx, parent_impl.def_id()) {
None
} else {
Some(Err(parent_impl.def_id()))
@@ -2075,7 +2076,7 @@ fn check_impl_items_against_trait<'tcx>(
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);
if !is_implemented && !tcx.impl_is_default(impl_id) {
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
if !trait_item.defaultness.has_value() {
missing_items.push(trait_item);
} else if associated_type_overridden {
@@ -2222,7 +2223,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
// caught by case 1.
match rty.is_representable(tcx, sp) {
Representability::SelfRecursive(spans) => {
let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id);
for span in spans {
err.span_label(span, "recursive without indirection");
}
+2 -2
View File
@@ -417,7 +417,7 @@ fn check_impl<'tcx>(
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
let trait_ref =
fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref);
let obligations = ty::wf::trait_obligations(
let obligations = traits::wf::trait_obligations(
fcx,
fcx.param_env,
fcx.body_id,
@@ -596,7 +596,7 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
let wf_obligations = predicates
.predicates
.iter()
.flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
.flat_map(|p| traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
for obligation in wf_obligations.chain(default_obligations) {
debug!("next obligation cause: {:?}", obligation.cause);
+7 -4
View File
@@ -7,9 +7,10 @@
use rustc::middle::region;
use rustc::infer;
use rustc::traits::misc::{can_type_implement_copy, CopyImplementationError};
use rustc::traits::predicate_for_trait_def;
use rustc::traits::{self, ObligationCause, TraitEngine};
use rustc::ty::adjustment::CoerceUnsizedInfo;
use rustc::ty::util::CopyImplementationError;
use rustc::ty::TypeFoldable;
use rustc::ty::{self, Ty, TyCtxt};
@@ -91,7 +92,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) {
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
match param_env.can_type_implement_copy(tcx, self_type) {
match can_type_implement_copy(tcx, param_env, self_type) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
let item = tcx.hir().expect_item(impl_hir_id);
@@ -284,7 +285,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
for field in coerced_fields {
let predicate = tcx.predicate_for_trait_def(
let predicate = predicate_for_trait_def(
tcx,
param_env,
cause.clone(),
dispatch_from_dyn_trait,
@@ -543,7 +545,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate = tcx.predicate_for_trait_def(
let predicate = predicate_for_trait_def(
tcx,
param_env,
cause,
trait_def_id,
+35 -34
View File
@@ -23,6 +23,7 @@
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::mir::mono::Linkage;
use rustc::traits;
use rustc::ty::query::Providers;
use rustc::ty::subst::GenericArgKind;
use rustc::ty::subst::{InternalSubsts, Subst};
@@ -1509,48 +1510,48 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
}
Node::GenericParam(param) => {
match &param.kind {
hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_gate::feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
unsupported_type
),
)
.emit();
};
}
if ty::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
struct_span_err!(
Node::GenericParam(param) => match &param.kind {
hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_gate::feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
unsupported_type
),
)
.emit();
};
}
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"the types of const generic parameters must derive `PartialEq` and `Eq`",
).span_label(
)
.span_label(
hir_ty.span,
format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
).emit();
}
ty
)
.emit();
}
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
ty
}
}
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
},
x => {
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);