|
1 | 1 | use super::internal_methods::InternalMethodPropertyContext; |
| 2 | +use crate::js_error; |
2 | 3 | use crate::value::JsVariant; |
3 | 4 | use crate::{ |
4 | 5 | Context, JsResult, JsSymbol, JsValue, |
@@ -888,22 +889,28 @@ impl JsObject { |
888 | 889 | context: &mut Context, |
889 | 890 | ) -> JsResult<()> { |
890 | 891 | // 1. If the host is a web browser, then |
891 | | - // a. Perform ? HostEnsureCanAddPrivateElement(O). |
| 892 | + // a. Perform ? HostEnsureCanAddPrivateElement(O). |
892 | 893 | context |
893 | 894 | .host_hooks() |
894 | 895 | .ensure_can_add_private_element(self, context)?; |
895 | 896 |
|
896 | | - // 2. Let entry be PrivateElementFind(O, P). |
| 897 | + // 2. If ? IsExtensible(O) is false, throw a TypeError exception. |
| 898 | + // NOTE: From <https://tc39.es/proposal-nonextensible-applies-to-private/#sec-privatefieldadd> |
| 899 | + if !self.is_extensible(context)? { |
| 900 | + return Err(js_error!( |
| 901 | + TypeError: "cannot add private field to non-extensible class instance" |
| 902 | + )); |
| 903 | + } |
| 904 | + |
| 905 | + // 3. Let entry be PrivateElementFind(O, P). |
897 | 906 | let entry = self.private_element_find(name, false, false); |
898 | 907 |
|
899 | | - // 3. If entry is not empty, throw a TypeError exception. |
| 908 | + // 4. If entry is not empty, throw a TypeError exception. |
900 | 909 | if entry.is_some() { |
901 | | - return Err(JsNativeError::typ() |
902 | | - .with_message("Private field already exists on prototype") |
903 | | - .into()); |
| 910 | + return Err(js_error!(TypeError: "private field already exists on prototype")); |
904 | 911 | } |
905 | 912 |
|
906 | | - // 4. Append PrivateElement { [[Key]]: P, [[Kind]]: field, [[Value]]: value } to O.[[PrivateElements]]. |
| 913 | + // 5. Append PrivateElement { [[Key]]: P, [[Kind]]: field, [[Value]]: value } to O.[[PrivateElements]]. |
907 | 914 | self.borrow_mut() |
908 | 915 | .private_elements |
909 | 916 | .push((name.clone(), PrivateElement::Field(value))); |
@@ -931,26 +938,47 @@ impl JsObject { |
931 | 938 | method, |
932 | 939 | PrivateElement::Method(_) | PrivateElement::Accessor { .. } |
933 | 940 | )); |
| 941 | + |
934 | 942 | let (getter, setter) = if let PrivateElement::Accessor { getter, setter } = method { |
935 | 943 | (getter.is_some(), setter.is_some()) |
936 | 944 | } else { |
937 | 945 | (false, false) |
938 | 946 | }; |
939 | 947 |
|
940 | 948 | // 2. If the host is a web browser, then |
941 | | - // a. Perform ? HostEnsureCanAddPrivateElement(O). |
| 949 | + // a. Perform ? HostEnsureCanAddPrivateElement(O). |
942 | 950 | context |
943 | 951 | .host_hooks() |
944 | 952 | .ensure_can_add_private_element(self, context)?; |
945 | 953 |
|
| 954 | + // 3. If ? IsExtensible(O) is false, throw a TypeError exception. |
| 955 | + // NOTE: From <https://tc39.es/proposal-nonextensible-applies-to-private/#sec-privatemethodoraccessoradd> |
| 956 | + if !self.is_extensible(context)? { |
| 957 | + return if getter || setter { |
| 958 | + Err(js_error!( |
| 959 | + TypeError: "cannot add private accessor to non-extensible class instance" |
| 960 | + )) |
| 961 | + } else { |
| 962 | + Err(js_error!( |
| 963 | + TypeError: "cannot add private method to non-extensible class instance" |
| 964 | + )) |
| 965 | + }; |
| 966 | + } |
| 967 | + |
946 | 968 | // 3. Let entry be PrivateElementFind(O, method.[[Key]]). |
947 | 969 | let entry = self.private_element_find(name, getter, setter); |
948 | 970 |
|
949 | 971 | // 4. If entry is not empty, throw a TypeError exception. |
950 | 972 | if entry.is_some() { |
951 | | - return Err(JsNativeError::typ() |
952 | | - .with_message("Private method already exists on prototype") |
953 | | - .into()); |
| 973 | + return if getter || setter { |
| 974 | + Err(js_error!( |
| 975 | + TypeError: "private accessor already exists on class instance" |
| 976 | + )) |
| 977 | + } else { |
| 978 | + Err(js_error!( |
| 979 | + TypeError: "private method already exists on class instance" |
| 980 | + )) |
| 981 | + }; |
954 | 982 | } |
955 | 983 |
|
956 | 984 | // 5. Append method to O.[[PrivateElements]]. |
|
0 commit comments