|
6 | 6 | //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file |
7 | 7 | //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. |
8 | 8 |
|
| 9 | +use std::assert_matches::assert_matches; |
9 | 10 | use std::cell::RefCell; |
10 | 11 | use std::fmt; |
11 | 12 | use std::ops::ControlFlow; |
@@ -890,12 +891,28 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { |
890 | 891 | fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) { |
891 | 892 | match qpath { |
892 | 893 | hir::QPath::Resolved(maybe_qself, path) => { |
| 894 | + // Visit the path before the self type since computing the ambient object lifetime default |
| 895 | + // for the latter requires all lifetime arguments of the trait ref to be already resolved. |
| 896 | + self.visit_path(path, id); |
893 | 897 | if let Some(qself) = maybe_qself { |
894 | | - // FIXME: Actually determine the ambient object lifetime defaults for the self ty! |
895 | | - let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope }; |
896 | | - self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 898 | + let container = match path.res { |
| 899 | + Res::Def(DefKind::AssocTy, def_id) => Some(( |
| 900 | + self.tcx.parent(def_id), |
| 901 | + &path.segments[..path.segments.len() - 1], |
| 902 | + )), |
| 903 | + _ => None, |
| 904 | + }; |
| 905 | + let object_lifetime_defaults = |
| 906 | + container.map_or(Vec::new(), |(def_id, segs)| { |
| 907 | + self.compute_ambient_object_lifetime_defaults(def_id, segs) |
| 908 | + }); |
| 909 | + if let Some(<) = object_lifetime_defaults.get(0) { |
| 910 | + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; |
| 911 | + self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 912 | + } else { |
| 913 | + self.visit_ty_unambig(qself); |
| 914 | + } |
897 | 915 | } |
898 | | - self.visit_path(path, id); |
899 | 916 | } |
900 | 917 | hir::QPath::TypeRelative(qself, segment) => { |
901 | 918 | // Resolving object lifetime defaults for type-relative paths requires full |
@@ -1060,51 +1077,53 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { |
1060 | 1077 | } |
1061 | 1078 |
|
1062 | 1079 | fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { |
1063 | | - let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else { |
1064 | | - bug!("expected GenericParam for object_lifetime_default"); |
| 1080 | + // Scan the bounds and where-clauses on parameters to extract bounds of the form `T: 'a` |
| 1081 | + // so as to determine the `ObjectLifetimeDefault` for each type parameter. |
| 1082 | + |
| 1083 | + let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) { |
| 1084 | + hir::Node::GenericParam(param) => match param.source { |
| 1085 | + hir::GenericParamSource::Generics => { |
| 1086 | + assert_matches!(param.kind, GenericParamKind::Type { .. }); |
| 1087 | + (tcx.hir_get_generics(tcx.local_parent(param_def_id)).unwrap(), &[][..]) |
| 1088 | + } |
| 1089 | + hir::GenericParamSource::Binder => return ObjectLifetimeDefault::Empty, |
| 1090 | + }, |
| 1091 | + // For Self ty params |
| 1092 | + hir::Node::Item(&hir::Item { |
| 1093 | + kind: hir::ItemKind::Trait(_, _, _, generics, bounds, _), |
| 1094 | + .. |
| 1095 | + }) => (generics, bounds), |
| 1096 | + _ => bug!("`object_lifetime_default` must only be called on type parameters"), |
1065 | 1097 | }; |
1066 | | - match param.source { |
1067 | | - hir::GenericParamSource::Generics => { |
1068 | | - let parent_def_id = tcx.local_parent(param_def_id); |
1069 | | - let generics = tcx.hir_get_generics(parent_def_id).unwrap(); |
1070 | | - |
1071 | | - // Scan the bounds and where-clauses on parameters to extract bounds |
1072 | | - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` |
1073 | | - // for each type parameter. |
1074 | | - match param.kind { |
1075 | | - GenericParamKind::Type { .. } => { |
1076 | | - let mut set = Set1::Empty; |
1077 | | - |
1078 | | - // Look for `type: ...` where clauses. |
1079 | | - for bound in generics.bounds_for_param(param_def_id) { |
1080 | | - // Ignore `for<'a> type: ...` as they can change what |
1081 | | - // lifetimes mean (although we could "just" handle it). |
1082 | | - if !bound.bound_generic_params.is_empty() { |
1083 | | - continue; |
1084 | | - } |
1085 | 1098 |
|
1086 | | - for bound in bound.bounds { |
1087 | | - if let hir::GenericBound::Outlives(lifetime) = bound { |
1088 | | - set.insert(lifetime.kind); |
1089 | | - } |
1090 | | - } |
1091 | | - } |
| 1099 | + let mut set = Set1::Empty; |
1092 | 1100 |
|
1093 | | - match set { |
1094 | | - Set1::Empty => ObjectLifetimeDefault::Empty, |
1095 | | - Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
1096 | | - Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
1097 | | - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
1098 | | - } |
1099 | | - _ => ObjectLifetimeDefault::Ambiguous, |
1100 | | - } |
1101 | | - } |
1102 | | - _ => { |
1103 | | - bug!("object_lifetime_default must only be called on a type parameter") |
1104 | | - } |
| 1101 | + let mut add_outlives_bounds = |bounds: &[hir::GenericBound<'_>]| { |
| 1102 | + for bound in bounds { |
| 1103 | + if let hir::GenericBound::Outlives(lifetime) = bound { |
| 1104 | + set.insert(lifetime.kind); |
1105 | 1105 | } |
1106 | 1106 | } |
1107 | | - hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, |
| 1107 | + }; |
| 1108 | + |
| 1109 | + add_outlives_bounds(bounds); |
| 1110 | + |
| 1111 | + // Look for `Type: ...` where clauses. |
| 1112 | + for bound in generics.bounds_for_param(param_def_id) { |
| 1113 | + // Ignore `for<'a> Type: ...` as they can change what |
| 1114 | + // lifetimes mean (although we could "just" handle it). |
| 1115 | + if bound.bound_generic_params.is_empty() { |
| 1116 | + add_outlives_bounds(&bound.bounds); |
| 1117 | + } |
| 1118 | + } |
| 1119 | + |
| 1120 | + match set { |
| 1121 | + Set1::Empty => ObjectLifetimeDefault::Empty, |
| 1122 | + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
| 1123 | + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
| 1124 | + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
| 1125 | + } |
| 1126 | + _ => ObjectLifetimeDefault::Ambiguous, |
1108 | 1127 | } |
1109 | 1128 | } |
1110 | 1129 |
|
@@ -1684,106 +1703,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { |
1684 | 1703 |
|
1685 | 1704 | debug!(?container); |
1686 | 1705 |
|
1687 | | - // Compute a vector of ambient object lifetime defaults, one for each type parameter, |
1688 | | - // per the rules initially given in RFCs 599 and 1156. Example: |
1689 | | - // |
1690 | | - // ```rust |
1691 | | - // struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U); |
1692 | | - // ``` |
1693 | | - // |
1694 | | - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default |
1695 | | - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) |
1696 | | - // and `dyn Baz` to `dyn Baz + 'static` (because there is no |
1697 | | - // such bound). |
1698 | | - // |
1699 | | - // Therefore, we would compute a vector like `['x, 'static]`. |
1700 | | - // Note that the vector only includes type parameters. |
1701 | | - let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segments)| { |
1702 | | - let in_body = { |
1703 | | - let mut scope = self.scope; |
1704 | | - loop { |
1705 | | - match *scope { |
1706 | | - Scope::Root { .. } => break false, |
1707 | | - |
1708 | | - Scope::Body { .. } => break true, |
1709 | | - |
1710 | | - Scope::Binder { s, .. } |
1711 | | - | Scope::ObjectLifetimeDefault { s, .. } |
1712 | | - | Scope::Opaque { s, .. } |
1713 | | - | Scope::Supertrait { s, .. } |
1714 | | - | Scope::TraitRefBoundary { s, .. } |
1715 | | - | Scope::LateBoundary { s, .. } => { |
1716 | | - scope = s; |
1717 | | - } |
1718 | | - } |
1719 | | - } |
1720 | | - }; |
1721 | | - |
1722 | | - let rbv = &self.rbv; |
1723 | | - let generics = self.tcx.generics_of(def_id); |
1724 | | - |
1725 | | - let set_to_region = |set: ObjectLifetimeDefault| match set { |
1726 | | - ObjectLifetimeDefault::Empty => { |
1727 | | - if in_body { |
1728 | | - None |
1729 | | - } else { |
1730 | | - Some(ResolvedArg::StaticLifetime) |
1731 | | - } |
1732 | | - } |
1733 | | - ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
1734 | | - ObjectLifetimeDefault::Param(param_def_id) => { |
1735 | | - fn param_to_depth_and_index( |
1736 | | - generics: &ty::Generics, |
1737 | | - tcx: TyCtxt<'_>, |
1738 | | - def_id: DefId, |
1739 | | - ) -> (usize, usize) { |
1740 | | - if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
1741 | | - let has_self = generics.parent.is_none() && generics.has_self; |
1742 | | - (0, index as usize - generics.parent_count - has_self as usize) |
1743 | | - } else if let Some(parent) = generics.parent { |
1744 | | - let parent = tcx.generics_of(parent); |
1745 | | - let (depth, index) = param_to_depth_and_index(parent, tcx, def_id); |
1746 | | - (depth + 1, index) |
1747 | | - } else { |
1748 | | - unreachable!() |
1749 | | - } |
1750 | | - } |
1751 | | - |
1752 | | - let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
1753 | | - segments[segments.len() - depth - 1] |
1754 | | - .args |
1755 | | - .and_then(|args| args.args.get(index)) |
1756 | | - .and_then(|arg| match arg { |
1757 | | - GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(), |
1758 | | - _ => None, |
1759 | | - }) |
1760 | | - } |
1761 | | - ObjectLifetimeDefault::Ambiguous => None, |
1762 | | - }; |
1763 | | - generics |
1764 | | - .own_params |
1765 | | - .iter() |
1766 | | - .filter_map(|param| { |
1767 | | - match self.tcx.def_kind(param.def_id) { |
1768 | | - // Generic consts don't impose any constraints. |
1769 | | - // |
1770 | | - // We still store a dummy value here to allow generic parameters |
1771 | | - // in an arbitrary order. |
1772 | | - DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
1773 | | - DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), |
1774 | | - // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter |
1775 | | - // works. Ignore it because it can't have a meaningful lifetime default. |
1776 | | - DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, |
1777 | | - dk => bug!("unexpected def_kind {:?}", dk), |
1778 | | - } |
1779 | | - }) |
1780 | | - .map(set_to_region) |
1781 | | - .collect() |
| 1706 | + let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segs)| { |
| 1707 | + self.compute_ambient_object_lifetime_defaults(def_id, segs) |
1782 | 1708 | }); |
1783 | 1709 |
|
1784 | 1710 | debug!(?object_lifetime_defaults); |
1785 | 1711 |
|
1786 | | - let mut i = 0; |
| 1712 | + let has_self = container |
| 1713 | + .map(|(def_id, _)| self.tcx.generics_of(def_id)) |
| 1714 | + .is_some_and(|generics| generics.parent.is_none() && generics.has_self); |
| 1715 | + let mut i = has_self as usize; |
1787 | 1716 | for arg in generic_args.args { |
1788 | 1717 | match arg { |
1789 | 1718 | // We've already visited all lifetime arguments at the start. |
@@ -1915,6 +1844,110 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { |
1915 | 1844 | } |
1916 | 1845 | } |
1917 | 1846 |
|
| 1847 | + /// Compute a vector of ambient object lifetime defaults, one for each type parameter, |
| 1848 | + /// per the rules initially given in RFCs 599 and 1156. |
| 1849 | + /// |
| 1850 | + /// # Example |
| 1851 | + /// |
| 1852 | + /// ```ignore (illustrative) |
| 1853 | + /// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U); |
| 1854 | + /// ``` |
| 1855 | + /// |
| 1856 | + /// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default |
| 1857 | + /// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) |
| 1858 | + /// and `dyn Baz` to `dyn Baz + 'static` (because there is no |
| 1859 | + /// such bound). |
| 1860 | + /// |
| 1861 | + /// Therefore, we would compute a vector like `['x, 'static]`. |
| 1862 | + /// Note that the vector only includes type parameters. |
| 1863 | + fn compute_ambient_object_lifetime_defaults( |
| 1864 | + &self, |
| 1865 | + def_id: DefId, |
| 1866 | + segments: &[hir::PathSegment<'_>], |
| 1867 | + ) -> Vec<Option<ResolvedArg>> { |
| 1868 | + let in_body = { |
| 1869 | + let mut scope = self.scope; |
| 1870 | + loop { |
| 1871 | + match *scope { |
| 1872 | + Scope::Root { .. } => break false, |
| 1873 | + |
| 1874 | + Scope::Body { .. } => break true, |
| 1875 | + |
| 1876 | + Scope::Binder { s, .. } |
| 1877 | + | Scope::ObjectLifetimeDefault { s, .. } |
| 1878 | + | Scope::Opaque { s, .. } |
| 1879 | + | Scope::Supertrait { s, .. } |
| 1880 | + | Scope::TraitRefBoundary { s, .. } |
| 1881 | + | Scope::LateBoundary { s, .. } => { |
| 1882 | + scope = s; |
| 1883 | + } |
| 1884 | + } |
| 1885 | + } |
| 1886 | + }; |
| 1887 | + |
| 1888 | + let generics = self.tcx.generics_of(def_id); |
| 1889 | + |
| 1890 | + let set_to_region = |set: ObjectLifetimeDefault| match set { |
| 1891 | + ObjectLifetimeDefault::Empty => { |
| 1892 | + if in_body { |
| 1893 | + None |
| 1894 | + } else { |
| 1895 | + Some(ResolvedArg::StaticLifetime) |
| 1896 | + } |
| 1897 | + } |
| 1898 | + ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
| 1899 | + ObjectLifetimeDefault::Param(param_def_id) => { |
| 1900 | + fn param_to_depth_and_index( |
| 1901 | + generics: &ty::Generics, |
| 1902 | + tcx: TyCtxt<'_>, |
| 1903 | + def_id: DefId, |
| 1904 | + ) -> (usize, usize) { |
| 1905 | + if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
| 1906 | + let has_self = generics.parent.is_none() && generics.has_self; |
| 1907 | + (0, index as usize - generics.parent_count - has_self as usize) |
| 1908 | + } else if let Some(parent) = generics.parent { |
| 1909 | + let parent = tcx.generics_of(parent); |
| 1910 | + let (depth, index) = param_to_depth_and_index(parent, tcx, def_id); |
| 1911 | + (depth + 1, index) |
| 1912 | + } else { |
| 1913 | + unreachable!() |
| 1914 | + } |
| 1915 | + } |
| 1916 | + |
| 1917 | + let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
| 1918 | + segments[segments.len() - depth - 1] |
| 1919 | + .args |
| 1920 | + .and_then(|args| args.args.get(index)) |
| 1921 | + .and_then(|arg| match arg { |
| 1922 | + GenericArg::Lifetime(lt) => self.rbv.defs.get(<.hir_id.local_id).copied(), |
| 1923 | + _ => None, |
| 1924 | + }) |
| 1925 | + } |
| 1926 | + ObjectLifetimeDefault::Ambiguous => None, |
| 1927 | + }; |
| 1928 | + generics |
| 1929 | + .own_params |
| 1930 | + .iter() |
| 1931 | + .filter_map(|param| { |
| 1932 | + match self.tcx.def_kind(param.def_id) { |
| 1933 | + // Generic consts don't impose any constraints. |
| 1934 | + // |
| 1935 | + // We still store a dummy value here to allow generic parameters |
| 1936 | + // in an arbitrary order. |
| 1937 | + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
| 1938 | + // `Self` type params share the `DefId` of the corresp. trait. |
| 1939 | + DefKind::TyParam | DefKind::Trait => { |
| 1940 | + Some(self.tcx.object_lifetime_default(param.def_id)) |
| 1941 | + } |
| 1942 | + // `Self` type params of trait aliases may show up here, ignore them. |
| 1943 | + DefKind::LifetimeParam | DefKind::TraitAlias => None, |
| 1944 | + dk => bug!("unexpected def_kind {:?}", dk), |
| 1945 | + } |
| 1946 | + }) |
| 1947 | + .map(set_to_region) |
| 1948 | + .collect() |
| 1949 | + } |
| 1950 | + |
1918 | 1951 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the |
1919 | 1952 | /// associated type name and starting trait. |
1920 | 1953 | /// For example, imagine we have |
|
0 commit comments