Change:
There is a crate inside of Fuchsia whose compile times increased from ~500ms to ~120s in the last month of Rust compiler updates. It hasn't been easy so far to provide a minimal example, but I will keep working at it. Some bisecting revealed that it actually consisted of two performance regressions, both affecting the time spent in : The first regression occurred in the rollup , and the second occurred sometime in the two weeks between changes ... There is heavy use of async/await in the code, and I've identified a couple places where taking out makes the compile finish right away. This makes me suspect for the first regression, but I'm not sure. I'll update the issue as I have more information.
Interestingly, removing from either of these places makes the compile much faster. If I leave both in, it's slow, but taking one or both out makes it faster. Maybe there's some kind of cycle being created when both are left in? In fact, switching on actually causes a cycle error to be reported when there wasn't one before. This is really weird to me, but it may be a red herring. Removing one or both of the calls (or calls to the methods that create the futures) doesn't resolve the cycle error, even though it resolves the slowdown. of the error, for completeness.
I don't have a lot more information to put here, except that the compile time seems to increase with the size of a particular call graph of async fns (it's not binary slow/fast, but different gradations of slow). This continues to make it hard to minimize. I did some profiling, and noticed a lot of time being spent collecting items in . Unfortunately I couldn't see what was calling that function. There was some speculation that it could be from (cc who suggested this). See for more details, and some flame graphs of the profiles I ran.
visited for T-compiler triage. Assigning P-high based on labels applied by niko as part of async-await triage. Removing nomination label too.

Discussion:
// that type, and when we finish expanding that type we remove the // its DefId. seen_opaque_tys: FxHashSet<DefId>, <ins> // Cache of all expansions we've seen so far. This is a critical // optimization for some large types produced by async fn trees. expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, </ins> primary_def_id: DefId, found_recursion: bool, tcx: TyCtxt<'tcx>,

} let substs = substs.fold_with(self); if self.seen_opaque_tys.insert(def_id) { <del> let generic_ty = self.tcx.type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx, substs); let expanded_ty = self.fold_ty(concrete_ty); </del> <ins> let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { Some(expanded_ty) => expanded_ty, None => { let generic_ty = self.tcx.type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx, substs); let expanded_ty = self.fold_ty(concrete_ty); self.expanded_cache.insert((def_id, substs), expanded_ty); expanded_ty } }; </ins> self.seen_opaque_tys.remove(&def_id); Some(expanded_ty) } else {

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Opaque(def_id, substs) = t.kind { self.expand_opaque_ty(def_id, substs).unwrap_or(t) <del> } else { </del> <ins> } else if t.has_projections() { </ins> t.super_fold_with(self) <ins> } else { t </ins> } } } let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), <ins> expanded_cache: FxHashMap::default(), </ins> primary_def_id: def_id, found_recursion: false, tcx: self,