mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
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:
@@ -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: ®ion::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: ®ion::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));
|
||||
}
|
||||
|
||||
@@ -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 ",
|
||||
|
||||
@@ -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,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,6 +1,5 @@
|
||||
//! Various code related to computing outlives relations.
|
||||
|
||||
pub mod env;
|
||||
pub mod free_region_map;
|
||||
pub mod obligations;
|
||||
pub mod verify;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(..) => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
+24
@@ -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
@@ -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]>) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ®ular_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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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 ¶m.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 ¶m.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);
|
||||
|
||||
Reference in New Issue
Block a user