@@ -1886,35 +1886,54 @@ impl<'a> Typechecker<'a> {
1886
1886
} else {
1887
1887
request_env. resource_entity_type ( )
1888
1888
} ;
1889
- let descendants = self . schema . get_entity_types_in_set ( rhs. iter ( ) ) ;
1890
- match ( var_euid, descendants) {
1891
- // We failed to lookup the descendants because the entity type
1892
- // is not declared in the schema, or we failed to get the
1893
- // principal/resource entity type because the request is
1894
- // unknown. We don't know if the euid would be in the
1895
- // descendants or not, so give it type boolean.
1896
- ( _, None ) | ( None , _) => {
1889
+ match var_euid {
1890
+ // We failed to get the principal/resource entity type because
1891
+ // we are typechecking a request for some action which isn't
1892
+ // declared in the schema. We don't know if the euid would be
1893
+ // in the descendants or not, so give it type boolean.
1894
+ None => {
1897
1895
let in_expr = ExprBuilder :: with_data ( Some ( Type :: primitive_boolean ( ) ) )
1898
1896
. with_same_source_info ( in_expr)
1899
1897
. is_in ( lhs_expr, rhs_expr) ;
1900
1898
if self . mode . is_partial ( ) {
1901
1899
TypecheckAnswer :: success ( in_expr)
1902
1900
} else {
1901
+ // This should only happen when doing partial validation
1902
+ // since we never construct the undeclared action
1903
+ // request environment otherwise.
1903
1904
TypecheckAnswer :: fail ( in_expr)
1904
1905
}
1905
1906
}
1906
- ( Some ( EntityType :: Specified ( var_name) ) , Some ( descendants) ) => {
1907
- Typechecker :: entity_in_descendants (
1908
- var_name,
1909
- descendants,
1910
- in_expr,
1911
- lhs_expr,
1912
- rhs_expr,
1913
- )
1907
+ Some ( EntityType :: Specified ( var_name) ) => {
1908
+ let all_rhs_known = rhs
1909
+ . iter ( )
1910
+ . all ( |e| self . schema . euid_has_known_entity_type ( e) ) ;
1911
+ if self . schema . is_known_entity_type ( var_name) && all_rhs_known {
1912
+ let descendants = self . schema . get_entity_types_in_set ( rhs. iter ( ) ) ;
1913
+ Typechecker :: entity_in_descendants (
1914
+ var_name,
1915
+ descendants,
1916
+ in_expr,
1917
+ lhs_expr,
1918
+ rhs_expr,
1919
+ )
1920
+ } else {
1921
+ let annotated_expr =
1922
+ ExprBuilder :: with_data ( Some ( Type :: primitive_boolean ( ) ) )
1923
+ . with_same_source_info ( in_expr)
1924
+ . is_in ( lhs_expr, rhs_expr) ;
1925
+ if self . mode . is_partial ( ) {
1926
+ // In partial schema mode, undeclared entity types are
1927
+ // expected.
1928
+ TypecheckAnswer :: success ( annotated_expr)
1929
+ } else {
1930
+ TypecheckAnswer :: fail ( annotated_expr)
1931
+ }
1932
+ }
1914
1933
}
1915
1934
// Unspecified entities will be detected by a different part of the validator.
1916
1935
// Still return `TypecheckFail` so that typechecking is not considered successful.
1917
- ( Some ( EntityType :: Unspecified ) , _ ) => TypecheckAnswer :: fail (
1936
+ Some ( EntityType :: Unspecified ) => TypecheckAnswer :: fail (
1918
1937
ExprBuilder :: with_data ( Some ( Type :: primitive_boolean ( ) ) )
1919
1938
. with_same_source_info ( in_expr)
1920
1939
. is_in ( lhs_expr, rhs_expr) ,
@@ -1966,7 +1985,7 @@ impl<'a> Typechecker<'a> {
1966
1985
} else if !lhs_is_action && !non_actions. is_empty ( ) {
1967
1986
self . type_of_non_action_in_entities (
1968
1987
lhs_euid,
1969
- non_actions. iter ( ) ,
1988
+ & non_actions,
1970
1989
in_expr,
1971
1990
lhs_expr,
1972
1991
rhs_expr,
@@ -2038,34 +2057,33 @@ impl<'a> Typechecker<'a> {
2038
2057
fn type_of_non_action_in_entities < ' b > (
2039
2058
& self ,
2040
2059
lhs : & EntityUID ,
2041
- rhs : impl IntoIterator < Item = & ' a EntityUID > + ' a ,
2060
+ rhs : & Vec < EntityUID > ,
2042
2061
in_expr : & Expr ,
2043
2062
lhs_expr : Expr < Option < Type > > ,
2044
2063
rhs_expr : Expr < Option < Type > > ,
2045
2064
) -> TypecheckAnswer < ' b > {
2046
2065
match lhs. entity_type ( ) {
2047
2066
EntityType :: Specified ( lhs_ety) => {
2048
- let rhs_descendants = self . schema . get_entity_types_in_set ( rhs) ;
2049
- match rhs_descendants {
2050
- Some ( rhs_descendants) if self . schema . is_known_entity_type ( lhs_ety) => {
2051
- Typechecker :: entity_in_descendants (
2052
- lhs_ety,
2053
- rhs_descendants,
2054
- in_expr,
2055
- lhs_expr,
2056
- rhs_expr,
2057
- )
2058
- }
2059
- _ => {
2060
- let annotated_expr =
2061
- ExprBuilder :: with_data ( Some ( Type :: primitive_boolean ( ) ) )
2062
- . with_same_source_info ( in_expr)
2063
- . is_in ( lhs_expr, rhs_expr) ;
2064
- if self . mode . is_partial ( ) {
2065
- TypecheckAnswer :: success ( annotated_expr)
2066
- } else {
2067
- TypecheckAnswer :: fail ( annotated_expr)
2068
- }
2067
+ let all_rhs_known = rhs
2068
+ . iter ( )
2069
+ . all ( |e| self . schema . euid_has_known_entity_type ( e) ) ;
2070
+ if self . schema . is_known_entity_type ( lhs_ety) && all_rhs_known {
2071
+ let rhs_descendants = self . schema . get_entity_types_in_set ( rhs. iter ( ) ) ;
2072
+ Typechecker :: entity_in_descendants (
2073
+ lhs_ety,
2074
+ rhs_descendants,
2075
+ in_expr,
2076
+ lhs_expr,
2077
+ rhs_expr,
2078
+ )
2079
+ } else {
2080
+ let annotated_expr = ExprBuilder :: with_data ( Some ( Type :: primitive_boolean ( ) ) )
2081
+ . with_same_source_info ( in_expr)
2082
+ . is_in ( lhs_expr, rhs_expr) ;
2083
+ if self . mode . is_partial ( ) {
2084
+ TypecheckAnswer :: success ( annotated_expr)
2085
+ } else {
2086
+ TypecheckAnswer :: fail ( annotated_expr)
2069
2087
}
2070
2088
}
2071
2089
}
0 commit comments