Skip to content

Minimize dependencies on trait and infer inside librustc #67970

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
47256b8
Remove private methods from TyCtxt impl block: rustc::infer::error_re…
cjgillot Jan 5, 2020
811adb5
Remove private methods from TyCtxt impl block: rustc::middle::stability.
cjgillot Jan 5, 2020
c1afe6a
Remove private methods from TyCtxt impl block: rustc::trait::object_s…
cjgillot Jan 5, 2020
0d9f4fb
Remove trivial function.
cjgillot Jan 5, 2020
640cae2
Remove private methods from TyCtxt impl block: rustc::ty::outlives.
cjgillot Jan 5, 2020
7118e33
Remove private methods from TyCtxt impl block: rustc::ty::print::pretty.
cjgillot Jan 5, 2020
d53bf7a
Make rustc::infer::error_reporting::{note_and_explain_free_region, no…
cjgillot Jan 5, 2020
0b1521e
Make rustc::traits::error_reporting::{recursive_type_with_infinite_si…
cjgillot Jan 5, 2020
7770bce
Make rustc::traits::object_safety::{astconv_object_safety_violations,…
cjgillot Jan 5, 2020
a80bff8
Move normalize_erasing_regions to rustc::ty.
cjgillot Jan 5, 2020
56a0aec
Move subst_and_normalize_erasing_regionsto rustc::ty.
cjgillot Jan 5, 2020
787cd54
Make traits::util::* free functions.
cjgillot Jan 5, 2020
73667af
Move ty::wf to traits.
cjgillot Jan 5, 2020
e905d5d
Move structural_match to rustc::traits.
cjgillot Jan 5, 2020
24d09c7
Move free_region_map to rustc::ty.
cjgillot Jan 5, 2020
86ec4b5
Move required_region_bounds to rustc::infer::opaque_types.
cjgillot Jan 5, 2020
f629baf
Move magic traits queries to rustc::traits::drop.
cjgillot Jan 5, 2020
700ac84
Rename traits::drop -> traits::misc.
cjgillot Jan 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions src/librustc/traits/drop.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
2 changes: 2 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod auto_trait;
mod chalk_fulfill;
pub mod codegen;
mod coherence;
pub mod drop;
mod engine;
pub mod error_reporting;
mod fulfill;
Expand Down Expand Up @@ -1243,6 +1244,7 @@ impl<'tcx> TraitObligation<'tcx> {
}

pub fn provide(providers: &mut ty::query::Providers<'_>) {
drop::provide(providers);
*providers = ty::query::Providers {
is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
Expand Down
1 change: 0 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3318,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,
Expand Down
Loading